了解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组中。