了解docker中的用户文件所有权:如何避免更改链接卷的权限

cbo*_*tig 63 linux permissions rstudio docker

考虑以下简单的Dockerfile:

FROM debian:testing
RUN  adduser --disabled-password --gecos '' docker
RUN  adduser --disabled-password --gecos '' bob 
Run Code Online (Sandbox Code Playgroud)

在一个没有别的工作目录.构建docker镜像:

docker build -t test .
Run Code Online (Sandbox Code Playgroud)

然后在容器上运行bash脚本,将工作目录链接到bob主目录中的新子目录:

docker run --rm -it -v $(pwd):/home/bob/subdir test 
Run Code Online (Sandbox Code Playgroud)

谁拥有subdir容器上的内容?在容器上,运行:

cd /home/bob/subdir
ls -l
Run Code Online (Sandbox Code Playgroud)

广告我们看到:

-rw-rw-r-- 1 docker docker 120 Oct 22 03:47 Dockerfile
Run Code Online (Sandbox Code Playgroud)

圣烟!docker拥有内容!回到容器外的主机上,我们看到我们的原始用户仍然拥有Dockerfile.让我们尝试修复bob主目录的所有权.在容器上,运行:

chown -R bob:bob /home/bob
ls -l 
Run Code Online (Sandbox Code Playgroud)

我们看到:

-rw-rw-r-- 1 bob bob 120 Oct 22 03:47 Dockerfile
Run Code Online (Sandbox Code Playgroud)

可是等等!在容器外面,我们现在运行ls -l

-rw-rw-r-- 1 1001 1001 120 Oct 21 20:47 Dockerfile
Run Code Online (Sandbox Code Playgroud)

我们不再拥有自己的文件.可怕的消息!


如果我们在上面的示例中只添加了一个用户,那么一切都会变得更顺利.出于某种原因,Docker似乎正在使其遇到的第一个非root用户拥有任何主目录(即使该用户是在较早的图像上声明的).同样,第一个用户是与我的家庭用户相同的所有权权限的用户.

问题1这是正确的吗?有人能指出我的文档,我只是根据上面的实验推测.

问题2:也许这只是因为它们在内核上都具有相同的数值,如果我在我的家庭用户不是id的系统上进行测试,1000那么权限会在每种情况下都被更改?

问题3:真正的问题当然是"我该怎么办?" 如果在给定的主机上bob登录bob,则应该能够运行容器,bob而不是在其主机帐户下更改文件权限.实际上,他实际上需要以用户docker身份运行容器以避免他的帐户被更改.

我听你问为什么我还有这样一个奇怪的Dockerfile呢?.我有时也想知道.我正在为webapp(RStudio-server)编写一个容器,允许不同的用户登录,这只是使用linux机器上的用户名和凭据作为有效的用户名.这给我带来了想要创建多个用户的不同寻常的动机.我可以通过仅在运行时创建用户来解决这个问题,并且一切都很好.但是,我使用添加了单个docker用户的基本映像,以便可以交互使用它而无需以root身份运行(根据最佳实践).这会破坏所有内容,因为该用户成为第一个用户并最终拥有所有内容,因此尝试以其他用户身份登录失败(应用无法启动,因为它缺少写入权限).chown首先运行启动脚本可以解决此问题,但代价是链接卷更改权限(如果我们链接卷,显然只会出现问题).

Jar*_*yth 56

我发现了两个选项:

清除所有的事情(做完你的工作后)

我已经完成了docker run -v `pwd`/shared:/shared image,容器已经创建了文件pwd/shared,这些文件是docker进程拥有的.但是,/shared仍归我所有.所以在docker过程中,我做到了

chown -R `stat -c "%u:%g" /shared` /shared

stat -c "%u:%g" /shared1000:1000在我的情况下返回,是uid:gid我的用户.即使1000docker conatainer中没有用户,id仍然存在(stat /shared如果您要求用户名,则只显示"unknown").

无论如何,chown乖乖地将内容的所有权转移/shared1000:1000(就其而言,不存在,但在容器之外,它就是我).所以我现在拥有所有文件.容器仍然可以根据需要修改,因为从它的角度来看,它是root.

一切都与世界很好.

docker run -u 所以创建的所有文件将自动拥有正确的所有者

另一种方法是-u在docker run上运行标志.

docker run -v `pwd`/shared:/shared -u `stat -c "%u:%g" /shared` ubuntu bash

这样,容器内的docker用户就是youruid:yourgid.

但是:这意味着放弃容器内的根权限(apt-get install等等).除非您使用该新uid创建用户并将其添加到root组中.


Chr*_*nel 25

那是对的吗?有人能指出我的文档,我只是根据上面的实验推测.

也许这仅仅是因为它们在内核上都具有相同的数值,如果我在我的家庭用户不是id 1000的系统上进行测试,那么在每种情况下都会更改权限?

阅读info coreutils 'chown invocation',可能会让您更好地了解文件权限/所有权的工作原理.

但是,基本上,您计算机上的每个文件都有一组固定的位,用于定义其权限和所有权.当你chown是一个文件时,你只是设置这些位.

当您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'
Run Code Online (Sandbox Code Playgroud)

但是,您可以chown使用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
Run Code Online (Sandbox Code Playgroud)

UID和GID位在文件本身上设置,因此当您在docker容器中挂载这些文件时,该文件具有与在主机上相同的所有者/组UID,但现在映射到/etc/passwd容器中,这是可能会成为一个不同的用户,除非它由root(UID 0)拥有.

当然,真正的问题是"我该怎么办?" 如果bob在给定主机上以bob身份登录,则他应该能够将容器作为bob运行,并且不能在其主机帐户下更改文件权限.实际上,他实际上需要以用户泊坞窗的形式运行容器,以避免他的帐户被更改.

看来,根据您当前的设置,您需要确保/etc/passwd主机上的UID>用户名与您的容器中的UID>用户名匹配,/etc/passwd如果您想要作为同一用户与您安装的用户目录进行交互那是在主机上登录的.

您可以使用特定用户ID创建用户useradd -u xxxx.Buuuut,这似乎是一个混乱的解决方案......

您可能必须提出不安装主机用户主目录的解决方案.


BBe*_*gui 9

因此,我最终在这篇文章中研究了如何将来自以 root身份运行的 docker 容器中的所有文件(由 root 拥有)的所有权恢复给我在主机中的非特权用户。

我需要容器内的进程以 root 身份运行,所以我不能在 docker run 上使用 -u。

我并不为我所做的感到自豪,但在我的 bash 脚本末尾,我添加了以下内容:

docker run --rm -it \
    --entrypoint /bin/sh \
    -e HOST_UID=`id -u` \
    -v ${HOST_FOLDER_OWNED_BY_ROOT}:/tmp \
    alpine:latest \
    -c 'chown -R ${HOST_UID}:${HOST_UID} /tmp/'
Run Code Online (Sandbox Code Playgroud)

让我们分解一些行:

  • 在容器内运行 /bin/sh:

--入口点/bin/sh

  • 将当前用户的 uid 作为环境变量传递给容器:

-e HOST_UID=`id -u`

  • 将您想要重新拥有的任何文件夹挂载回您的用户(填充由 root 拥有的文件,由以 root 运行的前一个容器输出),在这个新容器的/tmp:

-v ${HOST_FOLDER_OWNED_BY_ROOT}:/tmp

  • chown使用主机用户的 uid 在目标目录上递归运行(安装在 中的容器内/tmp):

-c 'chown -R ${HOST_UID}:${HOST_UID} /tmp/'

因此,有了这个,我将拥有的文件归还给了我当前的用户,而无需将权限“升级”到 root 或 sudo。

它很脏,但它起作用了。希望我有所帮助。