【问题标题】:how to correctly use system user in docker container如何在 docker 容器中正确使用系统用户
【发布时间】:2018-11-12 12:11:51
【问题描述】:

我正在像这样从我的 docker 映像启动容器:

$ docker run -it --rm --user=999:998 my-image:latest bash

其中 uid 和 gid 用于名为 sdp 的系统用户:

$ id sdp uid=999(sdp) gid=998(sdp) groups=998(sdp),999(docker)

但是:容器说“不”...

groups: cannot find name for group ID 998
I have no name!@75490c598f4c:/home/myfolder$ whoami
whoami: cannot find name for user ID 999

我做错了什么?

请注意,我需要在多个系统上运行基于此映像的容器,并且不能保证用户的 uid:gid 在各个系统中都是相同的,这就是为什么我需要在命令行而不是在Dockerfile。

提前致谢。

【问题讨论】:

  • 如果我理解正确,您可以使用 -u, docker run -it -u root --rm --name=999:998 my-image:latest 与特定用户一起进入 bash重击
  • 谢谢,赫曼特。您的回复让我注意到我在我随后编辑的问题中输入了错误的命令行。我一直在使用 --user 选项,和 -u 一样。
  • 为什么需要容器以特定系统用户身份运行?您是否尝试访问使用主机卷/绑定挂载挂载的内容并且需要避免权限问题?

标签: docker dockerfile


【解决方案1】:

1) 确保用户 999 对当前目录具有正确的权限,您需要在 docker 文件中尝试这样的操作 来自

RUN mkdir /home/999-user-dir && \
    chown -R 999:998 /home/999-user-dir
WORKDIR /home/999-user-dir
USER 999

尝试在不使用用户参数的情况下使用此图像启动容器,看看是否可行。

2) 其他原因可能是以下文件的权限问题,请确保您的群组998 对这些文件具有读取权限

-rw-r--r-- 1 root root 690 Jan 2 06:27 /etc/passwd -rw-r--r-- 1 root root 372 Jan 2 06:27 /etc/group

谢谢

【讨论】:

    【解决方案2】:

    当容器内的 /etc/passwd 或 /etc/group 文件中不存在 uid/gid 时,会发生这种错误。有多种方法可以解决这个问题。一种是直接将这些文件从您的主机映射到容器中,例如:

    $ docker run -it --rm --user=999:998 \
      -v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro \
      my-image:latest bash
    

    我不喜欢这种解决方案,因为容器文件系统中的文件现在可能拥有错误的所有权,从而导致潜在的安全漏洞和错误。

    通常,人们想要更改容器内的 uid/gid 的原因是因为他们将主机中的文件作为主机卷挂载到容器中,并希望两者之间的权限无缝。在这种情况下,我的解决方案是以 root 身份启动容器并使用一个调用如下脚本的入口点:

    if [ -n "$opt_u" ]; then
      OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
      NEW_UID=$(stat -c "%u" "$1")
      if [ "$OLD_UID" != "$NEW_UID" ]; then
        echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
        usermod -u "$NEW_UID" -o "$opt_u"
        if [ -n "$opt_r" ]; then
          find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
        fi
      fi
    fi
    

    以上内容来自我的base image 中包含的修复烫发脚本。发生的事情是将容器内用户的 uid 与挂载到容器(作为卷)中的文件或目录的 uid 进行比较。当这些 id 不匹配时,容器内的用户将被修改为与卷具有相同的 uid,并且容器内具有旧 uid 的任何文件都会被更新。我的入口点的最后一步是调用类似:

    exec gosu app_user "$@"
    

    这有点像以 app_user 身份运行“CMD”值的 su 命令,但使用一些 exec 逻辑将 pid 1 替换为“CMD”进程以更好地处理信号。然后我使用如下命令运行它:

    $ docker run -it --rm --user=0:0 -v /host/vol:/container/vol \
      -e RUN_AS app_user --entrypoint /entrypoint.sh \
      my-image:latest bash
    

    看看我链接到的基础镜像仓库,包括 nginx 的例子,它展示了这些部分是如何组合在一起的,并且避免了在生产环境中以 root 身份运行容器的需要(假设生产环境知道 uid/gid 的可以烘焙到映像中,或者您不在生产中挂载主机卷)。

    【讨论】:

    • 我试图挂载这两个“-v /etc/passwd:/etc/passwd:ro -v /etc/group:/etc/group:ro”,似乎还不够克服“权限被拒绝”。
    • @teoring 你到答案的第二段了吗?
    【解决方案3】:

    因此,在您的主机上,您可能会看到您的用户和组:

    $ cat /etc/passwd
    sdp:x:999:998::...
    

    但在容器内,您不会在/etc/passwd 中看到它们。

    这是预期的行为,主机和容器是完全分开的,只要您不将/etc/passwd 文件挂载到容器内(从安全角度来看,您不应该这样做)。

    现在,如果您在 Dockerfile 中指定了默认用户,--user 运算符将覆盖 USER 指令,因此您在容器中没有用户name,但请注意,指定uid:gid 选项表示容器拥有宿主机中具有相同uid 值的用户的权限。

    现在您的请求是不要在 Dockerfile 中指定用户 - 这应该不是问题。只要uid 与主机上的现有用户uid 匹配,就可以在运行时设置它。

    如果您必须在特权模式下运行某些容器 - 请考虑使用user namespace

    【讨论】:

      【解决方案4】:

      让我感到奇怪的是,没有内置的命令行选项可以简单地使用与主机“相同”的用户运行容器,这样文件权限就不会在挂载的目录中被弄乱。正如 OP 所提到的,-u $(id -u):$(id -g) 方法给出了“找不到组 ID 的名称”错误。

      我是 docker newb,但这是我一直在使用的方法,以防它帮助其他人:

      # See edit below before using this.
      docker run --rm -it -v /foo:/bar ubuntu:20.04 sh -c "useradd -m -s /bin/bash $USER && usermod -a -G sudo $USER && su - $USER"
      

      即添加具有匹配名称的用户 (useradd),使其成为 sudo (usermod),然后使用该用户 (su -) 打开终端。

      编辑:我刚刚发现这会在尝试使用apt 时导致E: List directory /var/lib/apt/lists/partial is missing. - Acquire (13: Permission denied) 错误。使用sudo 会产生错误-su: sudo: command not found,因为sudo 默认情况下不会安装在我使用的图像上。因此,该命令变得更加hacky,需要在启动时运行apt updateapt install sudo

      docker run --rm -it -v /foo:/bar ubuntu:20.04 sh -c "useradd -m -s /bin/bash $USER && usermod -a -G sudo $USER && apt update && apt install sudo && passwd -d $USER && su - $USER"
      

      不理想!我希望有一种更简单的方法来做到这一点(使用命令行选项,而不是创建新图像),但我还没有找到。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-03-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多