【问题标题】:Docker using gosu vs USERDocker 使用 gosu vs USER
【发布时间】:2016-08-15 08:23:25
【问题描述】:

Docker 总是有一个 USER 命令来以特定用户身份运行进程,但通常很多东西都必须以 ROOT 身​​份运行。

我见过很多使用ENTRYPOINTgosu 来降低进程运行的图像。

我对@9​​87654325@ 的需求仍然有些困惑。 USER 还不够吗?

我知道 Docker 1.10 在安全性方面发生了很大变化,但我仍然不清楚在 docker 容器中运行进程的推荐方法。

谁能解释我什么时候使用gosuUSER

谢谢

编辑:

Dockerbest practice guide不是很清楚:它说如果进程可以在没有权限的情况下运行,使用USER,如果你需要sudo,你可能想使用gosu。 这很令人困惑,因为可以在Dockerfile 中以ROOT 的身份安装各种东西,然后创建一个用户并为其赋予适当的权限,最后切换到该用户并以该用户身份运行CMD。 那么为什么我们需要 sudo 或 gosu 呢?

【问题讨论】:

    标签: docker dockerfile


    【解决方案1】:

    Dockerfiles 用于创建镜像。当您无法再在 Dockerfile 中的运行命令之间更改用户时,我认为 gosu 作为容器初始化的一部分更有用。

    创建镜像后,像 gosu 这样的东西允许您在容器内的入口点末尾删除 root 权限。您最初可能需要 root 访问权限来执行一些初始化步骤(修复 uid、主机安装的卷权限等)。然后一旦初始化,您就可以在没有 root 权限的情况下以 pid 1 的身份运行最终服务以干净地处理信号。


    编辑: 这是一个在 docker 和 jenkins 的镜像中使用 gosu 的简单示例:https://github.com/bmitch3020/jenkins-docker

    entrypoint.sh 查找 /var/lib/docker.sock 文件的 gid 并更新容器内 docker 用户的 gid 以匹配。这允许将映像移植到主机上的 gid 可能不同的其他 docker 主机。更改组需要容器内的 root 访问权限。如果我在 dockerfile 中使用了USER jenkins,我会被图像中定义的 docker 组的 gid 卡住,如果它与运行它的 docker 主机的 gid 不匹配,它将无法工作。但是在运行 gosu 所在的应用程序时可以删除 root 访问权限。

    在脚本结束时, exec 调用阻止 shell 派生 gosu,而是用该进程替换 pid 1。 Gosu 反过来做同样的事情,切换 uid 然后执行 jenkins 进程,以便它作为 pid 1 接管。这允许正确处理信号,否则会被 shell 忽略为 pid 1。

    【讨论】:

    • 当你运行这个并且运行器的 gid 为 0 时,entrypoint.sh 中的groupmod 命令失败并显示groupmod: GID '0' already exists 并且脚本继续运行。此时,jenkins 用户无法在容器中运行 docker。有什么建议吗?
    • 在这种情况下,我将构建两个图像。需要 root 的基础镜像和从第一个镜像中提取的 jenkins 镜像。您可以进行多阶段构建以将其全部包含在一个文件中。然后您可以与您的用户一起开始第二次构建。这也可以让您更早地制定权限。
    • @MichaelNoe 不确定我是否遵循多阶段示例。此处需要gosu,因为权限和用户 ID 的更改取决于运行时知识,您无法在构建时计算。同一个 Jenkins 镜像可以运行在多台主机上,主机上有不同的 docker GID。
    • 应该提出一些论据来解释为什么创建gosu 来替代标准su。我的第一反应是我不在乎也不想要一个 go 程序来代替标准的 unix 工具。
    • @JohanBoulé gosu repo 上的自述文件有帮助吗? github.com/tianon/gosu
    【解决方案2】:

    我使用 gosu 和 entrypoint.sh 是因为我希望容器中的用户与创建容器的用户具有相同的 UID。

    Docker Volumes and Permissions.

    我创建容器的目的是为了开发。我需要为 linux 构建,但我仍然想要本地(OS X)编辑、工具等的所有便利。我在容器内部和外部保持 UID 相同,它使文件所有权更加理智并防止一些错误(容器用户无法编辑挂载卷中的文件等)

    【讨论】:

    • 我不确定我是否关注这里:gosu 在容器中运行;它以 ROOT 身​​份运行,冒充另一个用户。该用户必须在图像中定义。那么这与“创建”图像的用户有什么关系呢?我可以看到,如果你创建一个与本地用户相同的用户,然后使用gosu作为这个用户运行,这样可以避免与本地挂载的卷发生冲突,但只是因为用户是同名的。
    • @MrE:用户不必在图像中定义。它可以在启动时在容器内使用useradd 创建。当用户名、uid 和 gid 作为环境变量传递到容器中时,可以将它们设置为与主机上的值匹配。
    • 我要补充一点,这个答案有助于避免递归地更改权限从主机装载的卷容器外部),其用户被继承所有挂载的文件。如答案中所述,这可以防止编辑文件。 – 例如当在 Minikube 上安装 Kubernetes 的 Pod volumes.hostPath 时会发生这种情况,从 Virtual 继承 docker 用户的 UID 和 GID机器,在 macOSWindows 上;嗯);在ENTRYPOINT 中使用gosu 会有所帮助。
    【解决方案3】:

    使用gosu 的优势还在于信号处理。您可以trap 例如SIGHUP 重新加载进程,就像您通常通过systemctl reload <process> 或类似实现的那样。

    【讨论】:

    • 我想这就是/sbin/tini的目的
    • 这就是为什么gosusu 更好,因为它执行的是执行而不是分叉。但它忽略了 OP 的问题,即为什么你想要 gosu 而不是在 Dockerfile 中设置 USER
    猜你喜欢
    • 1970-01-01
    • 2018-03-20
    • 2013-12-09
    • 2016-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 2020-11-13
    相关资源
    最近更新 更多