基于 Docker Image 实现普通用户 + sudo

1. 基于 ubuntu:22.04

官方 ubuntu:22.04 是一个极简镜像:没有预装 sudo,没有普通用户(只有 root 和一个 ubuntu 用户,UID 1000)。所以必须自己动手补齐。有两条路线:


路线一:写 Dockerfile 构建自己的镜像(推荐,可复用)

这是标准做法——以官方镜像为基础,加一层定制:

FROM ubuntu:22.04

# 避免安装过程中的交互提示卡住
ENV DEBIAN_FRONTEND=noninteractive

# 1. 安装 sudo(官方镜像里没有)
RUN apt-get update \
    && apt-get install -y sudo \
    && rm -rf /var/lib/apt/lists/*

# 2. 创建普通用户 dev(UID 1000,带家目录和 bash)
RUN useradd -m -s /bin/bash -u 1000 dev

# 3. 授予免密 sudo 权限
RUN echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev \
    && chmod 440 /etc/sudoers.d/dev

# 4. 默认以普通用户身份启动
WORKDIR /home/dev
USER dev

CMD ["/bin/bash"]

然后:

# 构建
docker build -t my-ubuntu:22.04 .

# 创建容器
docker run -itd --name mycontainer my-ubuntu:22.04

# 进入容器(进去就是 dev 用户)
docker exec -it mycontainer bash

验证:

dev@container:/home/dev$ whoami
dev
dev@container:/home/dev$ sudo apt-get update   # 免密,成功

加分项:让 UID 与宿主机用户一致

如果会挂载宿主机目录(-v),建议构建时传入宿主机 UID,避免权限问题:

ARG USER_UID=1000
RUN useradd -m -s /bin/bash -u ${USER_UID} dev

构建时:

docker build --build-arg USER_UID=$(id -u) -t my-ubuntu:22.04 .

路线二:不构建镜像,启动时现场配置(临时/一次性场景)

直接拿官方镜像跑一个容器,先进去手动装好 sudo、建好用户,之后都用 exec --user 进入:

# 1. 以 root 启动官方镜像
docker run -itd --name mycontainer ubuntu:22.04

# 2. 以 root 身份进入,做一次性配置
docker exec -it mycontainer bash

在容器内执行:

apt-get update && apt-get install -y sudo
useradd -m -s /bin/bash -u 1000 dev
echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev
chmod 440 /etc/sudoers.d/dev
exit

以后进入都指定普通用户:

docker exec -it --user dev -w /home/dev mycontainer bash

注意:这条路线的配置只存在于这个容器实例里。容器删掉就没了;想保留可以 docker commit mycontainer my-ubuntu:22.04 固化成镜像,但日常更推荐路线一(Dockerfile 可版本管理、可复现)。


路线三:docker-compose 场景

services:
  app:
    build: .            # 使用路线一的 Dockerfile
    container_name: mycontainer
    stdin_open: true
    tty: true

进入方式不变:docker exec -it mycontainer bash


关键结论

事项官方 ubuntu:22.04 的现状需要做的
sudo 命令❌ 未安装apt-get install -y sudo
普通用户❌ 没有可用的(ubuntu 用户无家目录配置、不在 sudoers)useradd -m -s /bin/bash dev
sudo 权限❌ 无/etc/sudoers.d/dev(权限 440)
默认身份rootDockerfile 里 USER dev,或 docker run/exec --user dev

总结

官方镜像只是地基,sudo + 普通用户这层必须由你在 Dockerfile 里加上去,之后 docker exec -it 容器名 bash 进去就是"普通用户身份 + 可 sudo 提权"的体验。

2. 基于 cuda*-devel-ubuntu:22.04 直接在容器实例内配置 sudo 普通用户

思路:先以 root 启动官方镜像 → 进容器做一次性配置(装 sudo、建用户、写 sudoers)→ 之后一律以普通用户身份进入。整个过程中,正在运行的容器会把配置保留在自己的可写层里,只要不删容器就一直有效。


第一步:以 root 身份启动官方镜像

docker run -itd \
  --name cuda-dev \
  --gpus all \
  --shm-size=16g \
  -v ${PWD}/workspace:/root/workspace \
  nvidia/cuda:12.4.1-devel-ubuntu22.04 \
  bash

注意:此时容器默认用户是 root。挂载点先放 /root/workspace,后面建好用户再调整,或直接在下一步把属主改给新用户。


第二步:进容器做一次性配置

docker exec -it cuda-dev bash

在容器内(root 身份)执行:

# 1. 安装 sudo
apt-get update && apt-get install -y sudo

# 2. 创建普通用户 dev(UID/GID 建议与宿主机用户一致,可用 id -u 在宿主机先查好)
groupadd -g 1000 dev
useradd -m -s /bin/bash -u 1000 -g 1000 dev

# 3. 授予免密 sudo
echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev
chmod 440 /etc/sudoers.d/dev

# 4.(可选)把挂载目录属主交给 dev
mkdir -p /home/dev/workspace
chown -R dev:dev /home/dev/workspace

exit

也可以不进入容器、在宿主机一条命令搞定:

docker exec cuda-dev bash -c '
  apt-get update -qq && apt-get install -y -qq sudo &&
  groupadd -g 1000 dev &&
  useradd -m -s /bin/bash -u 1000 -g 1000 dev &&
  echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev &&
  chmod 440 /etc/sudoers.d/dev
'

第三步:以后进入容器,显式指定普通用户

因为镜像没有 USER dev 指令(这是与 build 方案的关键区别),每次进入都要带 --user

docker exec -it --user dev -w /home/dev cuda-dev bash

容器内验证:

dev@container:~$ whoami
dev
dev@container:~$ sudo apt-get update     # 免密,成功
dev@container:~$ nvidia-smi              # GPU 正常

需要 root 排查时:

docker exec -it --user root cuda-dev bash

第四步(可选):把配置固化下来

上面的配置只存在于 cuda-dev 这一个容器实例的可写层中,容器一删就没了。两个应对办法:

办法一:docker commit 固化成镜像(不 build,但效果等同)

docker commit cuda-dev cuda-dev:configured

# 以后新容器直接从它启动,进去就有 dev 用户和 sudo
docker run -itd --name cuda-dev2 --gpus all --user dev -w /home/dev cuda-dev:configured bash

办法二:挂载一个初始化脚本,启动时自动配置

把配置写成脚本放在宿主机,启动时执行:

# 宿主机上准备 init.sh
cat > init.sh <<'EOF'
#!/bin/bash
if ! id dev &>/dev/null; then
  apt-get update -qq && apt-get install -y -qq sudo
  groupadd -g 1000 dev
  useradd -m -s /bin/bash -u 1000 -g 1000 dev
  echo "dev ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/dev
  chmod 440 /etc/sudoers.d/dev
fi
exec sleep infinity   # 保持容器运行
EOF
chmod +x init.sh

# 启动时挂载并作为入口执行
docker run -itd --name cuda-dev --gpus all --shm-size=16g \
  -v ${PWD}/init.sh:/init.sh:ro \
  -v ${PWD}/workspace:/home/dev/workspace \
  nvidia/cuda:12.4.1-devel-ubuntu22.04 \
  /init.sh

容器每次(重建后)启动都会自动完成配置,之后照常 docker exec -it --user dev cuda-dev bash 进入。


与 build 方案的对比

对比项不 build(本方案)Dockerfile build
配置生效位置单个容器实例的可写层(或 commit 出的镜像)镜像层,天然持久
进入容器每次都要 --user dev -w /home/dev直接 docker exec -it 容器 bash
可复现性差,删容器即丢失好,Dockerfile 即文档
适合场景临时调试、一次性环境、快速验证长期使用的开发环境

一句话总结: 不 build 的路径是"容器内 root 一次性配置 + 之后 docker exec --user dev 进入";如果这套环境要长期用或多台机器复现,建议 docker commit 固化,或者干脆回到 Dockerfile 方案——长期看后者更省心。

3. build image

基于 nvidia/cuda:*-devel-ubuntu22.04 构建带 sudo 普通用户的镜像:完整流程

目标

基于 NVIDIA 官方 ubuntu22.04 的 CUDA devel 镜像构建自己的镜像,使创建的容器满足:

  • 进入容器后默认是普通用户身份;
  • 该用户可以执行 sudo 提权;
  • GPU 正常使用。

前置条件:宿主机已装好 NVIDIA 驱动、Docker、nvidia-container-toolkit,且 docker run --rm --gpus all nvidia/cuda:12.4.1-base-ubuntu22.04 nvidia-smi 能正常输出 GPU 信息。


第一步:编写 Dockerfile

FROM nvidia/cuda:12.4.1-devel-ubuntu22.04

ENV DEBIAN_FRONTEND=noninteractive

# 1. 安装 sudo(官方镜像未预装)及常用工具
RUN apt-get update && apt-get install -y \
    sudo \
    vim git wget curl \
    && rm -rf /var/lib/apt/lists/*

# 2. 创建普通用户 dev(带家目录和 bash)
#    通过 ARG 支持构建时对齐宿主机 UID/GID,解决挂载目录权限问题
ARG USER_NAME=dev
ARG USER_UID=1000
ARG USER_GID=1000

RUN groupadd -g ${USER_GID} ${USER_NAME} \
    && useradd -m -s /bin/bash -u ${USER_UID} -g ${USER_GID} ${USER_NAME}

# 3. 授予免密 sudo 权限
RUN echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/${USER_NAME} \
    && chmod 440 /etc/sudoers.d/${USER_NAME}

# 4. 默认以普通用户身份启动容器
USER ${USER_NAME}
WORKDIR /home/${USER_NAME}

CMD ["/bin/bash"]

关键点说明:

配置作用注意
apt-get install sudo官方镜像没有 sudo,必须安装少了这步 sudo 无从谈起
useradd -m -s /bin/bash建用户并指定家目录、shell不加 -m 没有家目录;不加 -s 默认是 sh
/etc/sudoers.d/dev授权文件权限必须 chmod 440,否则 sudo 拒绝读取
NOPASSWD:ALL免密 sudo若要密码:dev ALL=(ALL) ALL + echo "dev:密码" | chpasswd
USER dev容器默认以普通用户启动少了这步进去还是 root

第二步:构建镜像

docker build \
  --build-arg USER_UID=$(id -u) \
  --build-arg USER_GID=$(id -g) \
  -t cuda-dev:12.4-u22.04 .

--build-arg 让容器内 dev 用户的 UID/GID 与宿主机当前用户一致,之后 -v 挂载目录时两边权限完全对齐,不会再出现"容器里创建的文件宿主机上属于 root"的问题。不挂载目录的话可以省略。


第三步:创建容器

docker run -itd \
  --name cuda-dev \
  --gpus all \
  --shm-size=16g \
  -v ${PWD}/workspace:/home/dev/workspace \
  cuda-dev:12.4-u22.04

参数说明:

  • --gpus all必需,把 GPU 暴露给容器;只用单卡可写 --gpus '"device=0"'
  • --shm-size=16g:PyTorch DataLoader 等场景需要,默认 64MB 会导致训练报错(可用 --ipc=host 替代);
  • -v:挂载工作目录(可选)。

第四步:进入容器

docker exec -it cuda-dev bash

由于 Dockerfile 里写了 USER dev,进去后直接就是普通用户,无需任何额外参数。

如需临时用 root 身份进入排查问题:

docker exec -it --user root cuda-dev bash

第五步:容器内验证

# 1. 身份是普通用户
dev@container:~$ whoami
dev

# 2. sudo 可用且免密
dev@container:~$ sudo apt-get update
# 正常执行

# 3. GPU 可用
dev@container:~$ nvidia-smi
# 显示 GPU 列表

# 4. CUDA 编译器可用(devel 镜像特有)
dev@container:~$ nvcc --version

常见问题速查

现象原因解决
sudo: command not found漏了 apt-get install sudo检查 Dockerfile 第 1 步
sudo 报错 /etc/sudoers.d/dev is world writable 或权限错误授权文件权限不是 440确认 chmod 440
进入容器后是 rootDockerfile 漏了 USER dev,或 exec 时带了 --user root补上 USER 指令重建
挂载目录中文件属主错乱容器内 UID 与宿主机不一致--build-arg USER_UID=$(id -u) 重建
容器里 nvidia-smi 失败没加 --gpus all,或宿主机 toolkit 没配好检查 run 参数和宿主机前置条件
nvcc 找不到误用了 runtime/base 镜像确认 tag 是 devel

全流程速查(可粘贴执行)

# ① 准备 Dockerfile(见第一步)

# ② 构建
docker build --build-arg USER_UID=$(id -u) --build-arg USER_GID=$(id -g) \
  -t cuda-dev:12.4-u22.04 .

# ③ 创建容器
docker run -itd --name cuda-dev --gpus all --shm-size=16g \
  -v ${PWD}/workspace:/home/dev/workspace cuda-dev:12.4-u22.04

# ④ 进入(普通用户身份,可 sudo)
docker exec -it cuda-dev bash

四步完成后,你就拥有一个"普通用户身份 + 免密 sudo + GPU 可用 + CUDA 编译工具链齐全"的开发容器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值