【问题标题】:Set docker image username at container creation time?在容器创建时设置 docker 镜像用户名?
【发布时间】:2017-08-15 15:57:19
【问题描述】:

我有一个已配置为运行代码的 OpenSuse 42.3 docker 映像。该映像有一个名为“myuser”的用户(除 root 用户),我在初始映像生成期间通过 Dockerfile 创建该用户。我有三个脚本文件,它们根据用户使用的操作系统从图像生成容器。

问题:容器中的用户名“myuser”能否设置为执行容器生成脚本的用户的用户名?

我的目标是让用户以交互方式进入容器并能够从容器内运行代码。该代码只是一个执行并具有一些 IO 的单个二进制文件,因此我希望可以从容器内访问用户的目录,以便他们可以导航到他们机器上的文件夹并运行代码以在他们的文件系统中生成输出。

以下是我到目前为止所构建的。我尝试在 linux 脚本调用docker run 期间设置 USER 环境变量,但这并没有将用户从“myuser”更改为“bob”(启动容器的主机上的用户名)。目录的安装似乎工作正常。我不确定是否有可能实现我的目标。

Linux 容器脚本:

username="$USER"
userID="$(id -u)"
groupID="$(id -g)"
home="${1:-$HOME}"

imageName="myImage:ImageTag"
containerName="version1Image"

docker run  -it -d --name ${containerName}  -u $userID:$groupID     \
            -e USER=${username} --workdir="/home/myuser"            \
            --volume="${home}:/home/myuser" ${imageName} /bin/bash  \

Mac 容器脚本:

username="$USER"
userID="$(id -u)"
groupID="$(id -g)"
home="${1:-$HOME}"

imageName="myImage:ImageTag"
containerName="version1Image"

docker run  -it -d --name ${containerName}                          \
            --workdir="/home/myuser"            \
            --v="${home}:/home/myuser" ${imageName} /bin/bash  \

Windows 容器脚本:

ECHO OFF
SET imageName="myImage:ImageTag"
SET containerName="version1Image"

docker run -it -d --name %containerName% --workdir="/home/myuser" -v="%USERPROFILE%:/home/myuser" %imageName% /bin/bash


echo "Container %containerName% was created."
echo "Run the ./startWindowsLociStream script to launch container"

【问题讨论】:

  • 为什么这个问题被否决了?
  • 很高兴知道它。赞成
  • 至少对于 linux 脚本来说,提供-u $userID:$groupID 就像你正在做的那样,应该足以让容器在宿主文件系统中写入人员。您在那里遇到的确切问题是什么?

标签: linux bash docker scripting


【解决方案1】:

以下代码已签入https://github.com/bmitch3020/run-as-user

我会在 entrypoint.sh 中处理这个问题,它会检查 /home/myuser 的所有权并更新容器内用户的 uid/gid。它可能看起来像:

#!/bin/sh

set -x
# get uid/gid
USER_UID=`ls -nd /home/myuser | cut -f3 -d' '`
USER_GID=`ls -nd /home/myuser | cut -f4 -d' '`

# get the current uid/gid of myuser
CUR_UID=`getent passwd myuser | cut -f3 -d: || true`
CUR_GID=`getent group myuser | cut -f3 -d: || true`

# if they don't match, adjust
if [ ! -z "$USER_GID" -a "$USER_GID" != "$CUR_GID" ]; then
    groupmod -g ${USER_GID} myuser
fi
if [ ! -z "$USER_UID" -a "$USER_UID" != "$CUR_UID" ]; then
    usermod -u ${USER_UID} myuser
    # fix other permissions
    find / -uid ${CUR_UID} -mount -exec chown ${USER_UID}.${USER_GID} {} \;
fi


# drop access to myuser and run cmd
exec gosu myuser "$@"

以下是相关 Dockerfile 中的一些内容:

FROM debian:9
ARG GOSU_VERSION=1.10

# run as root, let the entrypoint drop back to myuser
USER root

# install prereq debian packages
RUN apt-get update \
    && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        apt-transport-https \
        ca-certificates \
        curl \
        vim \
        wget \
    && apt-get clean \
    && rm -rf /var/lib/apt/lists/*

# Install gosu
RUN dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
    && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
    && chmod 755 /usr/local/bin/gosu \
    && gosu nobody true

RUN useradd -d /home/myuser -m myuser
WORKDIR /home/myuser

# entrypoint is used to update uid/gid and then run the users command
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD /bin/sh

然后要运行它,您只需将 /home/myuser 挂载为一个卷,它将调整入口点中的权限。例如:

$ docker build -t run-as-user . 
$ docker run -it --rm -v $(pwd):/home/myuser run-as-user /bin/bash

在该容器内,您可以运行 idls -l 来查看您是否可以访问 /home/myuser 文件。

【讨论】:

  • 有趣的方法。 +1
【解决方案2】:

用户名并不重要。重要的是 uid 和 gid 值。

容器内的用户 myuser 的 uid 为 1000(第一个非 root 用户 id)。因此,当您启动容器并从主机查看容器进程时,您将看到该容器归主机上 uid 为 1000 的任何用户所有。

您可以通过在运行容器后指定用户来覆盖它:

docker run --user 1001 ...

因此,如果您希望容器内的用户能够访问 uid 为 1005 的用户所拥有的主机上的文件,只需使用 --user 1005 运行容器即可。

要更好地了解用户如何在容器和主机之间进行映射,请查看这篇精彩的文章。 https://medium.com/@mccode/understanding-how-uid-and-gid-work-in-docker-containers-c37a01d01cf

【讨论】:

    【解决方案3】:

    首先(https://docs.docker.com/engine/reference/builder/#arg):

    警告:不建议使用构建时变量进行传递 诸如 github 密钥、用户凭据等秘密。构建时变量 具有 docker 历史记录的图像的任何用户都可以看到值 命令。

    但如果您仍然需要这样做,请阅读https://docs.docker.com/engine/reference/builder/#arg

    一个 Dockerfile 可能包含一个或多个 ARG 指令。例如, 以下是一个有效的 Dockerfile:

    FROM busybox
    ARG user1
    ARG buildno
    ...
    

    https://docs.docker.com/engine/reference/builder/#user:

    USER 指令设置用户名(或 UID)和可选的 运行映像和任何 RUN、CMD 时使用的用户组(或 GID) 以及 Dockerfile 中的 ENTRYPOINT 指令。

    USER <user>[:<group>] or
    USER <UID>[:<GID>]
    

    【讨论】:

    • 这不是容器创建时间,而是镜像构建时间?
    • 我不想在图像创建期间传递构建变量。我只是想将容器中的环境与运行容器的用户的环境对齐。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-07
    • 2019-08-03
    • 1970-01-01
    相关资源
    最近更新 更多