Docker和–userns-remap,如何pipe理卷的权限来共享主机和容器之间的数据?

在docker中,在容器内部创build的文件往往在从主机上检查它们时具有不可预知的所有权。 卷上文件的所有者默认为root(uid 0),但一旦非容器用户帐户被包含在容器中并写入文件系统,所有者就会从主机angular度来看或多或less随机。

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

典型的解决方法是

  • 在Dockerfiles中创build时强制用户的uid(非便携)
  • 将主机用户的UID作为环境variables传递给docker run命令,然后在入口点脚本的卷上运行一些chown命令。

这两个解决scheme都可以控制容器外的实际权限。

我期望用户命名空间是这个问题的最终解决scheme。 我已经运行了最近发布的版本1.10和–userns-remap设置到我的桌面帐户的一些testing。 不过,我不确定是否可以使挂载的文件更容易处理,恐怕事实恰恰相反。

假设我开始这个基本的容器

 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。 这个子用户似乎没有与我的实际普通用户以外的泊坞窗。 它没有映射回来。

由于在命名空间中发生的UID->sub-UID映射,本文前面提到的由主机和容器之间的UIDalignment组成的解决方法不再UID->sub-UID

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

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

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

  1. 使用固定的数字ID创build一些用户:

     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 
  2. /etc/subuid/etc/subgid文件中手动编辑自动生成的从属ID范围:

     ns1:500000:65536 

    (请注意,由于/etc/login.defs MAX_UIDMAX_GID限制,没有针对ns1-rootns1-user1logging)

  3. /etc/default/docker启用用户命名空间:

     DOCKER_OPTS="--userns-remap=ns1" 

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

    现在,在容器中有rootuser1 ,在主机 – ns1-rootns1-user1有相匹配的ID

    更新:为了保证非root用户在容器中有固定的ID(例如user1 1000:1000),在构build映像时显式创build它们。

试驾:

  1. 准备一个卷目录

     mkdir /vol1 chown ns1-root:ns1-root /vol1 
  2. 尝试从一个容器

     docker run --rm -ti -v /vol1:/vol1 busybox sh echo "Hello from container" > /vol1/file exit 
  3. 尝试从主机

     passwd ns1-root login ns1-root cat /vol1/file echo "can write" >> /vol1/file 

不便携式,看起来像一个黑客,但工程。

您可以通过使用docker cp命令来避免权限问题。

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

这里是你的例子切换到使用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 $ 

当我想将文件复制到一个容器中时,我发现命名卷很有用,正如这个问题所描述的那样。