| 名称 | tao-run-on-docker |
| 描述 | 在GPU主机上运行NVIDIA GPU容器工作负载的Docker约定 — NGC身份验证、–gpus标志、挂载模式、环境变量传递、容器检查、磁盘分离主机的数据根目录迁移,以及常见错误模式。当其他技能需要运行nvcr.io容器或GPU主机上的任何docker run命令时使用。触发关键词 — docker、docker run、nvcr.io、NGC、–gpus、nvidia-container-toolkit、container image、docker login、docker pull。 |
| 开源协议 | Apache-2.0 compatibility: 需要NVIDIA驱动580或更新版本、CUDA工具包13.0或更新版本、Docker和NVIDIA容器工具包1.19.0或更新版本,除非所选模型在runtime_requirements.gpu_host中声明了不同的最低要求。 metadata: |
| 版本 | “0.1.0” |
| 作者 | NVIDIA Corporation allowed-tools: Read Bash tags: - platform - docker |
适用于NVIDIA GPU工作负载的Docker
独立安装? 如果此会话不是由TAO技能库插件初始化的,请先运行
tao-setup技能(主机预检、凭据、跨技能发现)。
本技能记录了GPU容器工作负载所依赖的通用Docker约定。模型和数据技能指定什么镜像和什么命令要运行;本技能涵盖如何运行docker以满足GPU + NVIDIA容器要求。
来源:官方Docker CLI参考资料(https://docs.docker.com/reference/cli/docker/)和NVIDIA容器工具包文档。
先决条件
- 主机GPU运行时 — 默认情况下,NVIDIA驱动
>=580、CUDA工具包>=13.0和NVIDIA容器工具包>=1.19.0。如果所选模型的references/skill_info.yaml声明了runtime_requirements.gpu_host,请将这些值传递给tao-setup-nvidia-gpu-host。模型要求覆盖该工作流的默认值。 - Docker —
docker --version必须返回≥20.10。安装:https://docs.docker.com/engine/install/。 - 用于
nvcr.io/*拉取的NGC API密钥。从https://ngc.nvidia.com/获取。
SB="${TAO_SKILL_BANK_PATH:-${TAO_SKILL_BANK_ROOT:-$PWD}}"
SETUP_SCRIPT="${SB}/skills/platform/tao-setup-nvidia-gpu-host/scripts/setup-nvidia-gpu-host.sh"
bash "$SETUP_SCRIPT" --backend docker --check-only || {
echo "MISSING: TAO GPU host runtime is not ready."
echo "After user approval, run (append --yes for non-interactive agent runs):"
echo " bash \"$SETUP_SCRIPT\" --backend docker --install"
exit 1
}
docker --version
docker run --rm --runtime=nvidia --gpus all ubuntu nvidia-smi
[ -n "$NGC_KEY" ] || echo "NGC_KEY unset — cannot pull nvcr.io images"
如果所选模型声明了runtime_requirements.gpu_host,请将相应的--min-driver-version、--min-cuda-version和--min-container-toolkit-version值附加到检查和任何已批准的安装命令。不要将一个模型的覆盖应用于无关的工作流。
NGC身份验证
echo "$NGC_KEY" | docker login nvcr.io -u '$oauthtoken' --password-stdin
在~/.docker/config.json中跨重启持久化。在unauthorized错误时重新运行。
docker run — 标准标志
HOST_RESULTS=/host/results
HOST_UID="$(id -u)"
HOST_GID="$(id -g)"
HOST_USER_NAME="$(id -un)"
[ "$HOST_UID" -ne 0 ] || { echo "Refusing writable Docker launch as UID 0" >&2; exit 1; }
HOST_IDENTITY_ARGS=(--user "$HOST_UID:$HOST_GID")
for group_id in $(id -G); do
[ "$group_id" = "$HOST_GID" ] || HOST_IDENTITY_ARGS+=(--group-add "$group_id")
done
mkdir -p "$HOST_RESULTS/.tao-runtime/home/.cache"/{huggingface,torch,triton,torchinductor,matplotlib}
docker run \
--gpus all \
--rm \
--shm-size=8g \
"${HOST_IDENTITY_ARGS[@]}" \
-v /host/data:/data \
-v "$HOST_RESULTS:/results" \
-e HOME=/results/.tao-runtime/home \
-e USER="$HOST_USER_NAME" -e LOGNAME="$HOST_USER_NAME" \
-e XDG_CACHE_HOME=/results/.tao-runtime/home/.cache \
-e HF_HOME=/results/.tao-runtime/home/.cache/huggingface \
-e TORCH_HOME=/results/.tao-runtime/home/.cache/torch \
-e TRITON_CACHE_DIR=/results/.tao-runtime/home/.cache/triton \
-e TORCHINDUCTOR_CACHE_DIR=/results/.tao-runtime/home/.cache/torchinductor \
-e MPLCONFIGDIR=/results/.tao-runtime/home/.cache/matplotlib \
-e HF_TOKEN -e NGC_KEY \
<image> \
<command>
注释:
--gpus '\"device=0,1\"'— 特定GPU(双引号转义)。没有nvidia-container-toolkit时,会报错:could not select device driver "" with capabilities: [[gpu]]。--rm— 退出时清理容器;当你希望在退出后使用docker logs时省略它。--shm-size=8g— 否则torchrun + PyTorch DataLoader会耗尽默认的64 MB/dev/shm;为多GPU训练调整大小,如果仍然遇到Bus error,则增加(例如16g)。--user "$(id -u):$(id -g)"— 当绑定挂载可写时默认需要。防止根用户拥有的checkpoint树导致提交主机用户无法清理。- 对于标准可写绑定路径,拒绝UID
0。如果启动器本身是root,显式获取已验证的非root提交UID:GID;绝不要从输出目录所有者推断它。 --group-add <gid>— 保留对共享数据集和工作区的补充主机组访问。规范数组添加除主GID之外的每个主机组。HOME、USER、LOGNAME和缓存重定向 — 防止框架在用户覆盖后写入镜像拥有的位置(如/root)。在启动前在可写挂载上准备这些目录。USER/LOGNAME是必需的,而不仅仅是装饰性的:任意--userUID在镜像中没有/etc/passwd条目,并且torch 2.x在导入时调用getpass.getuser()(torch/_dynamo→ inductor缓存目录设置) — 如果没有设置这两个环境变量,容器在任何工作负载代码运行之前就会崩溃,并出现KeyError: 'getpwuid(): uid not found: <uid>'。任何非空名称都满足要求;该名称不需要存在于镜像中。-v host:container— 绑定挂载;命令只引用容器路径。-e VAR— 从父shell传递(如果已设置则不需要值)。对这种形式使用秘密。
容器名称冲突
如果名为X的容器已经存在,docker run --name X会失败。重用名称前的防御模式:
docker stop my-worker 2>/dev/null; docker rm my-worker 2>/dev/null
docker run --name my-worker ...
分离 + exec模式
对于同一容器上的多步骤工作流(下载→运行→后处理),避免重启成本:
HOST_RESULTS=/host/results
HOST_UID="$(id -u)"
HOST_GID="$(id -g)"
[ "$HOST_UID" -ne 0 ] || { echo "Refusing writable Docker launch as UID 0" >&2; exit 1; }
HOST_IDENTITY_ARGS=(--user "$HOST_UID:$HOST_GID")
for group_id in $(id -G); do
[ "$group_id" = "$HOST_GID" ] || HOST_IDENTITY_ARGS+=(--group-add "$group_id")
done
mkdir -p "$HOST_RESULTS/.tao-runtime/home/.cache"/{huggingface,torch,triton,torchinductor,matplotlib}
docker run -d --name <worker> \
--gpus all --shm-size=8g \
"${HOST_IDENTITY_ARGS[@]}" \
-v <host-data>:/data \
-v "$HOST_RESULTS:/results" \
-e HOME=/results/.tao-runtime/home \
-e USER="$(id -un)" -e LOGNAME="$(id -un)" \
-e XDG_CACHE_HOME=/results/.tao-runtime/home/.cache \
-e HF_HOME=/results/.tao-runtime/home/.cache/huggingface \
-e TORCH_HOME=/results/.tao-runtime/home/.cache/torch \
-e TRITON_CACHE_DIR=/results/.tao-runtime/home/.cache/triton \
-e TORCHINDUCTOR_CACHE_DIR=/results/.tao-runtime/home/.cache/torchinductor \
-e MPLCONFIGDIR=/results/.tao-runtime/home/.cache/matplotlib \
--entrypoint sh \
<image> -c "tail -f /dev/null"
docker exec <worker> <step_1>
docker exec <worker> <step_2>
docker stop <worker> && docker rm <worker>
拉取-如果缺少习语
docker image inspect <image> >/dev/null 2>&1 || docker pull <image>
用于发现的标签
标记容器以便以后进行过滤列表:
docker run --label tao-toolkit ...
docker ps --filter 'label=tao-toolkit'
挂载模式
容器期望在镜像定义的常规路径处获取其数据(通常为/data、/results、/workspace/checkpoints)。主机端是任意的。docker run内的命令只引用容器路径。
可写挂载所有权不变式
对于每个可写绑定挂载,默认情况下应以提交主机UID:GID运行。
仅在根容器可以创建更深的0755目录时,预先创建挂载根是不够的:删除受父目录权限控制,因此这些子树变得对主机用户不可访问。
容器--rm和docker rm仅删除容器状态;两者都不会删除或修复绑定挂载的checkpoint。
仅当文档或预检证明主机用户执行不兼容时,镜像才可以root身份运行。将此视为显式启动异常。隔离其可写输出,并在每次终端退出或取消后、在另一个实验开始之前,使所有权规范化。对于具有/bin/sh和chown的镜像,运行后修复为:
HOST_UID="$(id -u)"
HOST_GID="$(id -g)"
docker run --rm --user 0:0 --entrypoint /bin/sh \
-v /host/results:/owned-output \
<same-approved-image> \
-c 'chown -R "$1:$2" /owned-output' sh "$HOST_UID" "$HOST_GID"
对每个可写输出/缓存挂载应用修复。如果代理无法运行或验证所有权规范化,则不得使用root必需异常。切勿将chmod 777替换为正常修复。
环境变量约定
TAO类工作负载的常见传递变量(调用技能声明它需要哪些):
NGC_KEY—nvcr.io拉取;某些运行时也在运行时读取HF_TOKEN— 受限的HuggingFace模型下载AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY、AWS_ENDPOINT_URL— 容器内的S3 I/OWANDB_API_KEY— 可选的W&B日志记录
当变量在父shell中时,使用-e VAR(没有=value)。避免将秘密放在命令行上。
备选GPU选择:-e NVIDIA_VISIBLE_DEVICES=0,1(或all)和-e NVIDIA_DRIVER_CAPABILITIES=all而不是--gpus。--gpus标志在标准x86主机上是首选;env-var形式更旧,是runtime=nvidia(Tegra/Jetson)所需要的。
容器检查
docker ps # 仅运行中的容器
docker ps -a # 所有容器,包括已退出的
docker ps --filter status=running --format '{{.Names}} {{.Image}}'
docker logs <name_or_id> # stdout/stderr
docker logs -f <name_or_id> # 跟随(相当于tail -f)
docker logs --tail 100 <name_or_id> # 最后N行
docker inspect <name_or_id> # 完整配置、挂载、环境、网络、状态(JSON)
docker inspect --format '{{.State.Status}}' <name_or_id>
docker stats # 实时CPU/内存/网络/块I/O
docker stats --no-stream # 一次性快照,非交互式
docker inspect是容器挂载、环境、命令、网络和退出代码的权威来源。使用它来调试容器为何表现不如预期。
镜像管理
docker pull <image>
docker image ls
docker system df # Docker管理的镜像/层/卷使用情况
每个主机拉取一次;docker run重用缓存的镜像。NVIDIA镜像通常为5-40GB。
分离磁盘数据根目录迁移
一些云GPU提供商提供较小的根卷+较大的临时卷。Docker默认在根目录上写入/var/lib/docker — 大镜像会将其填满。检查:
df -h / # 根卷大小/可用空间
lsblk # 所有块设备及挂载点
如果/小于总镜像占用空间,并且其他位置挂载了更大的磁盘,请在拉取镜像之前进行迁移:
sudo systemctl stop docker
sudo mkdir -p <large_volume_path>/docker
sudo rsync -aP /var/lib/docker/ <large_volume_path>/docker/
sudo mv /var/lib/docker /var/lib/docker.old
sudo tee /etc/docker/daemon.json <<'EOF'
{ "data-root": "<large_volume_path>/docker" }
EOF
sudo systemctl start docker
docker info | grep 'Docker Root Dir'
sudo rm -rf /var/lib/docker.old
网络(多容器模式)
对于通过名称相互通信的微服务容器,创建docker网络并附加容器:
docker network create tao-net
docker run --network tao-net --name api ...
docker run --network tao-net --name worker ... # 可通过名称解析`api`
大多数TAO训练工作负载不需要这个 — 每个作业一个容器。
常见错误模式
could not select device driver "" with capabilities: [[gpu]] — NVIDIA容器工具包缺失或Docker没有为NVIDIA运行时配置。在用户批准后运行tao-setup-nvidia-gpu-host,添加--backend docker --install(对于非交互式代理运行,追加--yes),然后重新启动Docker。
unauthorized: authentication required 在docker pull时 — NGC密钥无效/缺失。重新运行docker login nvcr.io。
no space left on device — 首先确定哪些文件系统和存储类已满;绑定挂载的训练输出不会计入docker system df,也不通过修剪Docker镜像来修复:
df -h / /var/lib/docker <results_root>
docker system df
docker inspect <tao-container> --format '{{json .Mounts}}'
du -xhd1 <results_root> 2>/dev/null | sort -h
find <results_root> -maxdepth 3 -printf '%u:%g %m %s %p
' 2>/dev/null | head
对于绑定挂载,仅使用SDK保留路径或经过审查的所有权修复来清理已确认的最终作业目录;绝不要假设docker system prune会触及它们。对于Docker自己的根目录,如上所述迁移data-root。docker system prune -a --volumes是破坏性的,可能删除属于其他工作流的未使用镜像和卷,因此只能在用户明确批准并审查docker system df清单后运行。
Bus error / DataLoader worker exited unexpectedly — /dev/shm太小。使用--shm-size增加共享内存(例如--shm-size=16g)。
绑定挂载路径上的permission denied — 容器UID ≠ 主机UID,或者HOME/框架缓存仍指向镜像拥有的目录。使用上面的标准主机UID:GID映射和可写HOME/cache重定向。对于有文档的root必需镜像,在重试之前完成强制的运行后所有权规范化。
导入torch/torchvision时的KeyError: 'getpwuid(): uid not found: <uid>' — 容器以--user UID运行,但该UID在/etc/passwd中没有条目,也没有USER/LOGNAME环境变量,因此getpass.getuser()在导入时回退到pwd.getpwuid()。仅-e HOME=...不能修复它。保持UID:GID映射并使用标准身份环境块(-e USER=... -e LOGNAME=...+可写HOME+缓存重定向)。不要通过以root身份运行来解决;这会重新造成根拥有的输出危害。
docker run -d之后的Error: No such container: <name> — 容器在启动时崩溃。docker ps -a显示已退出;docker logs <name>可查看原因。调试时去掉--rm。
范围边界
本技能涵盖在GPU主机上运行docker的方法。特定平台的分层(如何进入主机、通过CLI包装器进行调度)位于:
tao-skill-bank:tao-run-on-brev— 通过brev exec在Brev实例上运行dockertao-skill-bank:tao-run-platform— 可选的Python层,用Job句柄、状态持久化和S3 I/O包装docker调用
模型和数据技能指定什么镜像和命令;它们将如何运行委托给本技能。