在Docker容器中如何使用sudo?

493

通常情况下,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软件包的错误。


1
只需将sudo组授予用户即可。http://askubuntu.com/questions/7477/how-can-i-add-a-new-user-as-sudoer-using-the-command-line - Regan
14个回答

387

当容器中没有sudo或apt-get命令时,您可以使用以下命令以root用户身份进入正在运行的容器。

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

20
这是一个比被采纳的答案更好的解决方案,符合原帖作者的需求。至少对我来说,这就是我一直在寻找的答案! - spikyjt
2
这是最好的答案,而不是用 Dockerfile 的困难方式来做。 - Marton Tatai
+1 我在 Docker 中更改权限时遇到了问题... 后来得知只有 root 用户才能执行此操作,这是完成它的唯一方法。这样,我就不需要使用 sudo 了! - Praveen
2
有人给这个人颁发奖章吧。 - Timo Huovinen
1
如果无法使用 /bin/bash,则请改用 /bin/sh。'docker exec -u root -t -i container_id /bin/sh' - azwar_akbar
显示剩余2条评论

380

刚刚解决了。正如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

17
在CentOS中无法正常工作。adduser命令会输出useradd的使用帮助。 - Emad
2
对于CentOS,您可以添加用户和组,然后在/etc/sudoers.d/下创建一个共享文件,并将该文件的权限设置为440。然后,在CentOS 6及以上版本中,用户将具有sudo访问权限。在CentOS 5中,您需要在/etc/sudoers中添加#includedir /etc/sudoers.d指令。 - FilBot3
3
这似乎在 Ubuntu 18.04 的 Docker 镜像上无法正常工作。 - viggy
我的用户叫做 bot。正确适配您的命令是:RUN useradd -m bot RUN echo "bot:bot" | chpasswd RUN adduser docker sudo 或许解释一下 echo "docker:docker" | chpasswd && adduser docker sudo 会更有帮助。 - Charlie Parker
adduser 命令用于创建新用户。要将 docker 用户添加到 sudo 组中,请使用 usermod -a -G sudo docker 命令。 - Aurélien Gâteau
显示剩余3条评论

147

其他答案对我没有用。我继续搜索,找到了一篇博客文章,介绍了一个团队如何在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/ - edesz
5
@WR 我认为你需要更改那行代码来写成 RUN sudo apt-get install -y tree。在将 USER 设置为除 root 以外的其他用户后,你需要使用 sudo 来执行任何需要 root 权限的命令。 - M. Scott Ford

88

对于那些遇到已经运行的容器问题的人,如果他们不想重新构建,则以下命令将以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

1
使用 docker execdocker commit 创建新镜像并不是一种特别可维护的方式;如果您需要出于任何原因重新创建镜像(比如原始基础镜像存在安全问题),这些手动步骤将无法被跟踪记录。 - David Maze
你是说把命令放在 Dockerfileentrypoint 中并重新构建会更好吗?我可能误解了你的观点,我开始时确实提到了“对于那些已经运行的容器出现此问题的人,他们不一定想要重新构建”,并且我特别警告过我们无法回溯的时刻。我已经添加了你的警告:“如果你从头开始重新构建,这些更改将不会重复”。还有其他需要添加的吗? - Chris

23

如果您想连接到容器并使用apt-get安装某些东西
首先,如我们的兄弟"Tomáš Záluský"所回答的那样

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

然后尝试执行

RUN apt-get update 或 apt-get '任何你想要的'

对我来说有效,希望对大家有用。


15
被接受的答案不同,我使用usermod

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

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

更新后记得保存镜像。使用docker ps获取当前运行中的 Docker 的<CONTAINER ID>和<IMAGE>,然后运行docker commit -m "添加了sudo用户" <CONTAINER ID> <IMAGE>以保存 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

12

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

docker exec -u root -it f83b5c5bf413 ash
"f83b5c5bf413 是我的容器ID,这里是来自我的终端的工作示例:
enter image description here"

11

以下是我如何使用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/bash
  • sed命令对/etc/sudoers文件进行内联更新,以允许fooroot用户无需密码访问sudo组。
  • sed命令禁用了#includedir指令,这将防止任何子目录中的文件覆盖这些内联更新。

7

主要思想是您需要根据容器创建一个root用户。

主要命令:

RUN echo "bot:bot" | chpasswd
RUN adduser bot sudo

第一个命令发送字面字符串bot:botchpasswd,然后创建用户名为bot的用户,并将密码设置为botchpasswd做了以下操作:

The chpasswd command reads a list of user name and password pairs from standard input and uses this information to update a group of existing users. Each line is of the format:

user_name:password

By default the supplied password must be in clear-text, and is encrypted by chpasswd. Also the password age will be updated, if present.

第二个命令我假设将用户bot添加为sudo。
完整的docker容器以供尝试:
FROM continuumio/miniconda3
# FROM --platform=linux/amd64 continuumio/miniconda3

MAINTAINER Brando Miranda "me@gmail.com"

RUN apt-get update \
  && apt-get install -y --no-install-recommends \
    ssh \
    git \
    m4 \
    libgmp-dev \
    opam \
    wget \
    ca-certificates \
    rsync \
    strace \
    gcc \
    rlwrap \
    sudo

# https://github.com/giampaolo/psutil/pull/2103

RUN useradd -m bot
# format for chpasswd user_name:password
RUN echo "bot:bot" | chpasswd
RUN adduser bot sudo

WORKDIR /home/bot
USER bot
#CMD /bin/bash

运行Dockerfile时出现以下错误:/bin/sh: useradd: 找不到命令。不知道为什么。 - Berni

7

这可能并不适用于所有图像,但某些图像已经包含一个root用户,例如在jupyterhub/singleuser图像中。对于该图像,只需执行以下操作:

USER root
RUN sudo apt-get update

2
对于镜像"fabric8/java-centos-openjdk8-jdk",只需在RUN命令之前添加USER root即可解决我的问题,甚至不需要添加sudo。 - Marco Martins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接