了解docker中的用户文件所有权:如何避免更改链接的卷的权限
考虑以下简单的Dockerfile:
FROM debian:testing RUN adduser --disabled-password --gecos '' docker RUN adduser --disabled-password --gecos '' bob
在没有别的工作目录。 build立docker形象:
docker build -t test .
然后在容器上运行一个bash脚本,将工作目录链接到bob的主目录上的新子目录:
docker run --rm -it -v $(pwd):/home/bob/subdir test
谁拥有容器上的subdir
的内容? 在容器上运行:
cd /home/bob/subdir ls -l
我们看到的广告:
-rw-rw-r-- 1 docker docker 120 Oct 22 03:47 Dockerfile
圣烟! docker
拥有的内容! 回到容器外部的主机上,我们看到我们原来的用户仍然拥有Dockerfile
。 让我们尝试解决bob
主目录的所有权问题。 在容器上运行:
chown -R bob:bob /home/bob ls -l
我们看到:
-rw-rw-r-- 1 bob bob 120 Oct 22 03:47 Dockerfile
可是等等! 在容器外面,我们现在运行ls -l
-rw-rw-r-- 1 1001 1001 120 Oct 21 20:47 Dockerfile
我们不再拥有自己的文件。 可怕的消息!
如果我们在上面的例子中只添加了一个用户,那么一切都会更加顺利。 出于某种原因,Docker似乎正在创build它遇到的第一个非root用户所拥有的任何主目录(即使该用户是在较早的映像中声明的)。 同样, 第一个用户是与我的家庭用户相同的所有权限。
问题1是否正确? 有人可以指点我这个文件,我只是基于上述的实验猜测。
问题2 :也许这只是因为它们在内核上都有相同的数值,而且如果我在家庭用户不是id 1000
的系统上testing,那么在每种情况下权限都会改变?
问题3 :真正的问题当然是“我该怎么办? 如果bob
在给定的主机上以bob
身份login,他应该能够运行该容器作为bob
并且没有在其主机帐户下更改文件权限。 就目前而言,他实际上需要将容器作为用户docker
来运行,以避免帐号被更改。
我听到你问我为什么有这么奇怪的Dockerfile吗? 。 我有时候也好奇 我正在编写一个webapp(RStudio-server)的容器,允许不同的用户login,它只是使用linux机器上的用户名和凭证作为有效的用户名。 这给我带来了想要创build多个用户的不同寻常的动机。 我可以通过在运行时创build用户来解决这个问题,并且很好。 但是,我使用添加了单个docker
用户的基本映像,以便可以交互方式使用而不以root身份运行(按照最佳实践)。 这会毁掉一切,因为该用户成为第一个用户,并最终拥有一切,所以尝试login为其他用户失败(应用程序无法启动,因为它没有写权限)。 让启动脚本首先运行chown
解决了这个问题,但代价是链接的卷更改了权限(显然,如果我们正在连接卷,这只是一个问题)。
那是对的吗? 有人可以指点我这个文件,我只是猜测根据上述实验。
也许这只是因为它们在内核上都有相同的数值,而且如果我在家庭用户不是id 1000的系统上testing,那么在每种情况下都会改变权限?
阅读info coreutils 'chown invocation'
,这可能会让您更好地了解文件权限/所有权是如何工作的。
但是,基本上,你的机器上的每个文件都有一组定位它的权限和所有权。 当你chown
一个文件,你只是设置这些位。
当使用用户名或组名将文件分配给特定的用户/组时, chown
将在/etc/passwd
查找用户名和/etc/group
,以尝试将该名称映射到ID。 如果这些文件中不存在用户名/组名, chown
会失败。
root@dc3070f25a13:/test# touch test root@dc3070f25a13:/test# ll total 8 drwxr-xr-x 2 root root 4096 Oct 22 18:15 ./ drwxr-xr-x 22 root root 4096 Oct 22 18:15 ../ -rw-r--r-- 1 root root 0 Oct 22 18:15 test root@dc3070f25a13:/test# chown test:test test chown: invalid user: 'test:test'
但是,您可以使用ID将文件分配给您想要的任何内容(当然,在某些正整数上限内),是否在您的计算机上存在与这些ID一起存在的用户/组。
root@dc3070f25a13:/test# chown 5000:5000 test root@dc3070f25a13:/test# ll total 8 drwxr-xr-x 2 root root 4096 Oct 22 18:15 ./ drwxr-xr-x 22 root root 4096 Oct 22 18:15 ../ -rw-r--r-- 1 5000 5000 0 Oct 22 18:15 test
UID和GID位在文件本身上设置,因此,当您在Docker容器中安装这些文件时,该文件具有与主机上相同的所有者/组UID,但现在映射到/etc/passwd
容器,这可能是一个不同的用户,除非它是由根(UID 0)拥有的。
真正的问题当然是,“我该怎么办? 如果bob在给定的主机上以bob身份login,他应该能够运行该容器作为bob,并且没有在其主机帐户下更改文件权限。 就目前而言,他实际上需要将容器作为用户docker来运行,以避免帐号被更改。
看起来就像你目前的设置,你需要确保你的主机上的/etc/passwd
中的用户名>用户名与你的容器/etc/passwd
UID>用户名匹配,如果你想和您挂载的用户目录与在主机上login的用户相同。
您可以使用useradd -u xxxx
创build具有特定用户标识的用户。 Buuuut,这看起来像一个混乱的解决scheme…
您可能不得不想出一个不挂载主机用户主目录的解决scheme。
我find了两个选项:
把所有的东西(做完你的工作之后)
我已经完成docker run -v `pwd`/shared:/shared image
,并且容器已经在pwd/shared
内创build了docker进程拥有的文件。 不过, /shared
仍然归我所有。 所以在docker过程中,我是这么做的
chown -R `stat -c "%u:%g" /shared` /shared
stat -c "%u:%g" /shared
在我的情况下返回1000:1000
,是我用户的uid:gid
。 即使docker conatainer中没有用户1000
,id也在那里(如果您要求用户名, stat /shared
只是说“未知”)。
无论如何, chown
乖乖地将/shared
内容的所有权转移到1000:1000
(就其而言,它不存在,但在容器外部,这是我)。 所以我现在拥有所有的文件。 如果需要的话,容器还是可以修改的,因为从它的angular度来看,它是root
。
世界一切都好。
docker run -u
所以创build的所有文件将自动拥有合适的所有者
另一种方法是在-u
上运行-u
标志。
docker run -v `pwd`/shared:/shared -u `stat -c "%u:%g" /shared` ubuntu bash
这样,容器中的youruid:yourgid
用户就是youruid:yourgid
。
但是:这意味着放弃容器内的root权限( apt-get install
等)。 除非你用这个新的uid创build一个用户,并把它添加到root
组中。