如何在 docker 容器中使用 sudo?

Posted

技术标签:

【中文标题】如何在 docker 容器中使用 sudo?【英文标题】:How to use sudo inside a docker container? 【发布时间】:2014-11-08 19:57:32 【问题描述】:

通常,docker 容器使用用户 root 运行。我想使用不同的用户,使用 docker 的 USER 指令没问题。但是这个用户应该能够在容器内使用 sudo。缺少此命令。

这是一个用于此目的的简单 Dockerfile:

FROM ubuntu:12.04

RUN useradd docker && echo "docker:docker" | chpasswd
RUN mkdir -p /home/docker && chown -R docker:docker /home/docker

USER docker
CMD /bin/bash

运行这个容器,我使用用户 'docker' 登录。当我尝试使用 sudo 时,找不到该命令。所以我尝试使用

在我的 Dockerfile 中安装 sudo
RUN apt-get install sudo

这导致 无法找到包 sudo

【问题讨论】:

只需给用户 sudo 组。 askubuntu.com/questions/7477/… 【参考方案1】:

刚刚收到。正如 regan 所指出的,我必须将用户添加到 sudoers 组。但主要原因是我忘记更新存储库缓存,所以 apt-get 找不到 sudo 包。它现在正在工作。这是完整的代码:

FROM ubuntu:12.04

RUN apt-get update && \
      apt-get -y install sudo

RUN useradd -m docker && echo "docker:docker" | chpasswd && adduser docker sudo

USER docker
CMD /bin/bash

【讨论】:

在 centos 中不起作用。 adduser 命令吐出useradd 的使用帮助 对于 CentOS,您可以添加用户和组,然后在 /etc/sudoers.d/ 下创建一个分片文件,并将该文件的权限设置为 440。然后用户将在 CentOS 6 及更高版本下拥有 sudo 访问权限。 5 你必须在/etc/sudoers 中添加#includedir /etc/sudoers.d 指令 对我不起作用。我有这些错误: E: 无法打开锁定文件 /var/lib/apt/lists/lock - open (13: Permission denied) E: Unable to lock directory /var/lib/apt/lists/ 这似乎不适用于 Ubuntu 18.04 docker 映像【参考方案2】:

当容器中 sudo 和 apt-get 均不可用时,您也可以使用命令以 root 用户身份跳转到正在运行的容器中

docker exec -u root -t -i container_id /bin/bash

【讨论】:

这对于 OP 可能想要实现的目标来说是一个更好的解决方案,即使接受的答案给出了请求的解决方案。至少,这是我一直在寻找的答案! 这是最好的答案,而不是用 dockerfile 来做这件事。 +1 我在更改 docker 内的权限时遇到问题。我知道只有 root 用户才能执行此操作,这是完成此操作的唯一方法。这样我就不需要sudo了! 有人给这个人一枚勋章【参考方案3】:

其他答案对我不起作用。我一直在搜索并找到了一个blog post,它涵盖了一个团队如何在 docker 容器内以非 root 用户运行。

这是 TL;DR 版本:

RUN apt-get update \
 && apt-get install -y sudo

RUN adduser --disabled-password --gecos '' docker
RUN adduser docker sudo
RUN echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers

USER docker

# this is where I was running into problems with the other approaches
RUN sudo apt-get update 

我为此使用了FROM node:9.3,但我怀疑其他类似的容器库也可以。

【讨论】:

我正在使用ubuntu:bionic-20180724.1。我使用了这种方法,但是在上述方法之后,它不允许我安装另一个包。我在上面的Dockerfile 上附加了一行,以便安装一个带有:RUN apt-get install -y tree 的包。但是,它给了我这个错误信息:Step xxxx/xxxx : RUN apt-get install -y tree ---> Running in j5e6gsvwfafa Reading package lists... E: Could not open lock file /var/lib/apt/lists/lock - open (13: Permission denied) E: Unable to lock directory /var/lib/apt/lists/ @WR 我认为您需要将该行更改为 RUN sudo apt-get install -y tree。将USER 设置为root 以外的其他值后,您需要将sudo 用于任何需要root 权限的命令。【参考方案4】:

对于已经运行的容器存在此问题并且不一定要重建的任何人,以下命令连接到具有 root 权限的正在运行的容器:

docker exec -ti -u root container_name bash

您还可以使用其 ID 而不是其名称进行连接,方法是通过以下方式找到它:

docker ps -l

要保存您的更改,以便在您下次启动容器(或 docker-compose 集群)时它们仍然存在 - 请注意,如果您从头开始重建,这些更改将不会重复:

docker commit container_id image_name

要回滚到以前的图像版本(警告:这会删除历史记录而不是追加到末尾,因此要保留对当前图像的引用,请先使用可选步骤对其进行标记):

docker history image_name
docker tag latest_image_id my_descriptive_tag_name  # optional
docker tag desired_history_image_id image_name

启动未运行的容器并以 root 身份连接:

docker run -ti -u root --entrypoint=/bin/bash image_id_or_name -s

从正在运行的容器中复制:

docker cp <containerId>:/file/path/within/container /host/path/target

要导出图像的副本:

docker save container | gzip > /dir/file.tar.gz

您可以使用以下方式恢复到另一个 Docker 安装:

gzcat /dir/file.tar.gz | docker load

它更快,但需要更多空间来不压缩,使用:

docker save container | dir/file.tar

还有:

cat dir/file.tar | docker load

【讨论】:

使用docker execdocker commit 来创建一个新镜像并不是一个特别可维护的路径;如果您出于任何原因需要重新创建映像(例如原始基础映像中存在安全问题),则不会在任何地方跟踪这些手动步骤。 您是说将命令放在Dockerfileentrypoint 中并重建会更好吗?我可能误解了您的观点,我确实从“对于已经运行的容器遇到此问题的任何人,并且他们不一定想要重建”开始,并且我特别警告我们不能回溯的那一刻。我已经添加了您的警告“如果您从头开始重建,这些更改将不会重复”。你还有什么要补充的吗?【参考方案5】:

如果你想连接到容器并安装一些东西 使用 apt-get 首先是我们兄弟“Tomáš Záluský”的上述回答

docker exec -u root -t -i container_id /bin/bash

然后尝试

运行 apt-get update 或 apt-get 'anything you want'

它对我有用 希望对大家有用

【讨论】:

【参考方案6】:

以下是我使用ubuntu:18.04 的基本映像设置非root 用户的方法:

RUN \
    groupadd -g 999 foo && useradd -u 999 -g foo -G sudo -m -s /bin/bash foo && \
    sed -i /etc/sudoers -re 's/^%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
    sed -i /etc/sudoers -re 's/^root.*/root ALL=(ALL:ALL) NOPASSWD: ALL/g' && \
    sed -i /etc/sudoers -re 's/^#includedir.*/## **Removed the include directive** ##"/g' && \
    echo "foo ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers && \
    echo "Customized the sudoers file for passwordless access to the foo user!" && \
    echo "foo user:";  su - foo -c id

上面的代码会发生什么:

用户和组foo 已创建。 用户foo 被添加到foosudo 组中。 uidgid 设置为 999 的值。 主目录设置为/home/foo。 shell 设置为/bin/bashsed 命令对/etc/sudoers 文件进行内联更新,以允许fooroot 用户无密码访问sudo 组。 sed 命令禁用#includedir 指令,该指令将允许子目录中的任何文件覆盖这些内联更新。

【讨论】:

【参考方案7】:

如果容器内无法访问 SUDOapt-get,您可以在运行容器时使用以下选项。

docker exec -u root -it f83b5c5bf413 ash

"f83b5c5bf413" 是我的容器 ID & 这里是来自我的终端的工作示例:

【讨论】:

【参考方案8】:

与accepted answer 不同,我使用usermod 代替。

假设已经在 docker 中以 root 身份登录,并且“fruit”是我要添加的新的非 root 用户名,只需运行以下命令:

apt update && apt install sudo
adduser fruit
usermod -aG sudo fruit

更新后记得保存图片。使用docker ps获取当前运行的docker的,然后运行docker commit -m "added sudo user" &lt;CONTAINER ID&gt; &lt;IMAGE&gt;保存docker镜像。

然后测试:

su fruit
sudo whoami

或者在启动docker时以非root用户直接登录(确保先保存图片)进行测试:

docker run -it --user fruit <IMAGE>
sudo whoami

您可以使用sudo -k重置密码提示时间戳

sudo whoami # No password prompt
sudo -k # Invalidates the user's cached credentials
sudo whoami # This will prompt for password

【讨论】:

【参考方案9】:

这可能不适用于所有图像,但某些图像已经包含 root 用户,例如在 jupyterhub/singleuser 图像中。使用该图像很简单:

USER root
RUN sudo apt-get update

【讨论】:

对于图像“fabric8/java-centos-openjdk8-jdk”,只需在 RUN 命令解决我的问题之前添加 USER root,甚至不需要添加 sudo【参考方案10】:

如果您有一个以 root 身份运行的容器运行需要访问 sudo 命令的脚本(您无法更改),您只需在 $PATH 中创建一个新的 sudo 脚本,该脚本调用传递的命令。

例如在你的 Dockerfile 中:

RUN if type sudo 2>/dev/null; then \ 
     echo "The sudo command already exists... Skipping."; \
    else \
     echo -e "#!/bin/sh\n\$@" > /usr/sbin/sudo; \
     chmod +x /usr/sbin/sudo; \
    fi

【讨论】:

根据您使用的 docker 映像(在我的情况下为 Ubuntu:18.04),您可能需要从 echo 中删除 -e。否则它将出现在文件本身中,使其无法正常工作。 好主意,但是如果原始命令使用 sudo 选项,例如sudo -E ls,这将不起作用。它将尝试执行-E ls【参考方案11】:

没有关于如何在 CentOS 上执行此操作的答案。 在 Centos 上,您可以在 Dockerfile 中添加以下内容

RUN echo "user ALL=(root) NOPASSWD:ALL" > /etc/sudoers.d/user && \
    chmod 0440 /etc/sudoers.d/user

【讨论】:

但是这个命令还是失败了:bash Step 6/8 : RUN echo "user ALL=(root) NOPASSWD:ALL" &gt; /etc/sudoers.d/user &amp;&amp; chmod 0440 /etc/sudoers.d/user ---&gt; Running in daea0aae031c /bin/sh: 1: cannot create /etc/sudoers.d/user: Permission denied 这基本上使你的“非root”用户等同于root,只要攻击者知道在他们的命令前加上sudo。它比以 root 身份运行要好一些,但我通常不建议在 Docker 设置中这样做。

以上是关于如何在 docker 容器中使用 sudo?的主要内容,如果未能解决你的问题,请参考以下文章

Docker容器进入的4种方式

如何在centos docker容器中支持sshd

如何根据镜像过滤docker进程

如何使用非 root 用户设置 cronjob?

免sudo使用docker命令

如何将运行在 Docker 容器中的 Flyway 连接到运行在 Docker 容器中的数据库?