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):
-
使用固定的数字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
-
在
/etc/subuid
和/etc/subgid
文件中手动编辑自动生成的从属ID范围:ns1:500000:65536
(请注意,由于
/etc/login.defs
MAX_UID
和MAX_GID
限制,没有针对ns1-root
和ns1-user1
logging) -
在
/etc/default/docker
启用用户命名空间:DOCKER_OPTS="--userns-remap=ns1"
重启守护进程
service docker restart
,确保/var/lib/docker/500000.500000
目录已经创build。现在,在容器中有
root
和user1
,在主机 –ns1-root
和ns1-user1
有相匹配的ID更新:为了保证非root用户在容器中有固定的ID(例如user1 1000:1000),在构build映像时显式创build它们。
试驾:
-
准备一个卷目录
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
不便携式,看起来像一个黑客,但工程。
您可以通过使用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 $
当我想将文件复制到一个容器中时,我发现命名卷很有用,正如这个问题所描述的那样。