首页 文章

Docker和--userns-remap,如何管理卷权限以在主机和容器之间共享数据?

提问于
浏览
60

在docker中,在容器内创建的文件在从主机检查时往往具有不可预测的所有权 . 默认情况下,卷上文件的所有者是root(uid 0),但只要非root用户帐户涉及容器并写入文件系统,所有者就会从主机角度变得或多或少随机 .

当您需要使用调用docker命令的同一用户帐户从主机访问卷数据时,这是一个问题 .

典型的解决方法是

  • 在Dockerfiles中创建时强制用户uID(非可移植)

  • 将主机用户的UID作为环境变量传递给 docker run 命令,然后在入口点脚本中的卷上运行一些 chown 命令 .

这两种解决方案都可以控制容器外的实际权限 .

我希望用户命名空间是这个问题的最终解决方案 . 我已经使用最近发布的版本1.10和--userns-remap设置到我的桌面帐户运行了一些测试 . 但是,我不确定它是否可以使安装卷上的文件所有权更容易处理,我担心它实际上可能正好相反 .

假设我启动这个基本容器

docker run -ti -v /data debian:jessie /bin/bash
echo 'hello' > /data/test.txt
exit

然后检查来自主机的内容:

ls -lh /var/lib/docker/100000.100000/volumes/<some-id>/_data/

-rw-r--r-- 1 100000 100000 6 Feb  8 19:43 test.txt

这个数字'100000'是我的主机用户的子UID,但由于它与我的用户的UID不对应,我仍然无法在没有权限的情况下编辑test.txt . 此子用户似乎与docker之外的实际常规用户没有任何关联 . 它没有映射回来 .

由于名称空间中出现的 UID->sub-UID 映射,本文前面提到的由主机和容器之间的UID对齐组成的变通方法不再起作用 .

那么,有没有办法在启用用户命名空间的情况下运行docker(为了提高安全性),同时仍然可以让运行docker的主机用户拥有在卷上生成的文件?

2 回答

  • 3

    如果您可以提前预先安排用户和组,则可以以特定方式分配UID和GID,以便主机用户对应容器内的命名空间用户 .

    这是一个例子(Ubuntu 14.04,Docker 1.10):

    • 使用固定数字ID创建一些用户:
    useradd -u 5000 ns1
    
    groupadd -g 500000 ns1-root
    groupadd -g 501000 ns1-user1
    
    useradd -u 500000 -g ns1-root ns1-root
    useradd -u 501000 -g ns1-user1 ns1-user1 -m
    
    • /etc/subuid/etc/subgid 文件中手动编辑自动生成的从属ID范围:
    ns1:500000:65536
    

    (注意_1486097_和_1486098_没有记录,因为 MAX_UID/etc/login.defs 中的 MAX_GID 限制)

    • /etc/default/docker 中启用用户名称空间:
    DOCKER_OPTS="--userns-remap=ns1"
    

    重启守护进程 service docker restart ,确保已创建 /var/lib/docker/500000.500000 目录 .

    Now, inside containers you have root and user1, and on the host -- ns1-root and ns1-user1, with matching IDs

    UPDATE: 为了保证非root用户在容器中具有固定ID(例如user1 1000:1000),在映像构建期间显式创建它们 .

    试驾:

    • 准备卷目录
    mkdir /vol1
    chown ns1-root:ns1-root /vol1
    
    • 从容器中试用
    docker run --rm -ti -v /vol1:/vol1 busybox sh
    echo "Hello from container" > /vol1/file
    exit
    
    • 从主持人那里试试
    passwd ns1-root
    login ns1-root
    cat /vol1/file
    echo "can write" >> /vol1/file
    

    不便携,看起来像黑客,但有效 .

  • 35

    您可以使用docker cp command来避免权限问题 .

    所有权设置为目的地的用户和主要组 . 例如,使用UID:root用户的GID创建复制到容器的文件 . 复制到本地计算机的文件是使用调用docker cp命令的用户的UID:GID创建的 .

    这是您的示例切换为使用 docker cp

    $ docker run -ti -v /data debian:jessie /bin/bash
    root@e33bb735a70f:/# echo 'hello' > /data/test.txt
    root@e33bb735a70f:/# exit
    exit
    $ docker volume ls
    DRIVER              VOLUME NAME
    local               f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93
    $ sudo ls -l /var/lib/docker/100000.100000/volumes/f073d0e001fb8a95ad8d919a5680e72b21a457f62a40d671b63c62ae0827bf93/_data
    total 4
    -rw-r--r-- 1 100000 100000 6 Oct  6 10:34 test.txt
    $ docker ps -a
    CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS                          PORTS               NAMES
    e33bb735a70f        debian:jessie       "/bin/bash"         About a minute ago   Exited (0) About a minute ago                       determined_hypatia
    $ docker cp determined_hypatia:/data/test.txt .
    $ ls -l test.txt 
    -rw-r--r-- 1 don don 6 Oct  6 10:34 test.txt
    $ cat test.txt
    hello
    $
    

    但是,如果您只想从容器中读取文件,则不需要指定的卷 . 此示例使用命名容器而不是命名卷:

    $ docker run -ti --name sandbox1 debian:jessie /bin/bash
    root@93d098233cf3:/# echo 'howdy' > /tmp/test.txt
    root@93d098233cf3:/# exit
    exit
    $ docker cp sandbox1:/tmp/test.txt .
    $ ls -l test.txt
    -rw-r--r-- 1 don don 6 Oct  6 10:52 test.txt
    $ cat test.txt
    howdy
    $
    

    当我想将文件复制到容器中时,我发现命名卷很有用,如this question中所述 .

相关问题