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) |
| 默认身份 | root | Dockerfile 里 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 |
| 进入容器后是 root | Dockerfile 漏了 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 编译工具链齐全"的开发容器。

4253

被折叠的 条评论
为什么被折叠?



