GPU 软件

使用 NVIDIA Container Toolkit 运行 Docker GPU 容器

我们的 Ubuntu 镜像已预装 Docker 和 NVIDIA Container Toolkit。下面介绍如何为每个容器分配它所需的 GPU,并且只分配这些 GPU。

本页内容
  1. 检查 Docker 和 Container Toolkit
  2. 为容器分配全部或部分 GPU
  3. 在 Docker Compose 中预留 GPU
  4. 选择 CUDA 或 NGC 基础镜像
  5. 为 PyTorch 提供足够的共享内存
  6. AMD GPU:ROCm 中的对应做法
  7. 故障排查

借助 NVIDIA Container Toolkit 运行 Docker GPU 工作负载只需一个参数,但实际部署还需要多做几步:为每个容器选择 GPU、在 Docker Compose 中预留 GPU、选择与驱动匹配的基础镜像,以及为 PyTorch 提供足够的共享内存。我们的 Ubuntu 镜像已预装 Docker 和该工具包。AMD 服务器则改用设备参数,文末附近会介绍。

检查 Docker 和 Container Toolkit

docker --version
nvidia-ctk --version
docker info | grep -i runtimes
docker run --rm --gpus all ubuntu nvidia-smi

最后一条命令应输出与主机上相同的 GPU 表格。Container Toolkit 会把主机的驱动挂载到容器中,因此镜像中从不包含驱动,只需包含应用程序所用的 CUDA 库。以非 root 用户身份操作时,请在 docker 前加上 sudo,或者加入 docker 组(该组的权限等同于 root)。

为容器分配全部或部分 GPU

# all GPUs
docker run --rm --gpus all ubuntu nvidia-smi -L
# GPUs 0 and 1 (the inner quotes are required because of the comma)
docker run --rm --gpus '"device=0,1"' ubuntu nvidia-smi -L
# one GPU by UUID, as printed by nvidia-smi -L on the host
docker run --rm --gpus device=GPU-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
  ubuntu nvidia-smi -L

在容器内,选中的 GPU 从 0 开始编号,因此主机上的 2 号和 3 号 GPU 会显示为 0 号和 1 号。要把某项服务固定到特定的 GPU 上,使用 UUID 最为稳妥。要在 8 卡服务器上运行 8 个相互独立的任务,请用 --gpus device=N 为每张 GPU 各启动一个容器。

对于使用 NVIDIA 运行时的容器,Container Toolkit 还会读取 NVIDIA_VISIBLE_DEVICES 变量:

docker run --rm --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=0,1 \
  ubuntu nvidia-smi -L

如果 /etc/docker/daemon.json 中的默认运行时是 nvidia,那么设置了该变量的镜像(NVIDIA 的 CUDA 镜像就是如此)即使不加 --gpus 也会获得所有 GPU;因此,需要限制 GPU 时,请显式设置该变量。CUDA_VISIBLE_DEVICES 则不同:它在容器内部,从已挂载的 GPU 中进行筛选。

在 Docker Compose 中预留 GPU

services:
  trainer:
    image: ubuntu:24.04
    command: nvidia-smi -L
    ipc: host
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              device_ids: ["0", "1"]
              capabilities: [gpu]

用 docker compose up 运行,输出中应列出两张 GPU。如果要按数量而不是按 ID 分配 GPU,请将 device_ids 替换为 count: all 或 count: 2;这两个键不能同时使用,并且必须设置 capabilities: [gpu]。如果 docker compose version 运行失败,请安装 Compose 插件:Docker 来自 Docker 官方软件源时安装 docker-compose-plugin,来自 Ubuntu 软件源时安装 docker-compose-v2。

即使 ufw 拒绝该端口,像 -p 8000:8000 这样发布的端口仍可从互联网访问,因为 Docker 会写入自己的防火墙规则。请以 -p 127.0.0.1:8000:8000 的形式发布服务(在 Compose 中写作 "127.0.0.1:8000:8000"),并在前面放置反向代理,具体做法见防火墙指南。

选择 CUDA 或 NGC 基础镜像

  • nvidia/cuda 镜像发布在 Docker Hub 上,分为三种类型:base(最精简的 CUDA 运行时)、runtime(增加 CUDA 库)和 devel(再增加编译器和头文件),部分镜像还包含 cuDNN。标签格式为 VERSION-FLAVOR-OS,例如 12.8.1-runtime-ubuntu24.04。
  • NGC 镜像(例如 nvcr.io/nvidia/pytorch)集成了经过调优的框架栈,按月发布标签,格式为 YY.MM-py3。其发行说明列出了每个标签所需的驱动。

请选择 CUDA 版本不高于主机上 nvidia-smi 所显示“CUDA Version”的标签;对于 Blackwell GPU,还需选择 CUDA 12.8 或更高版本。如果镜像所需的驱动比主机上的更新,容器会拒绝启动,并报出 unsatisfied condition: cuda>= 错误。驱动与 CUDA 版本一文解释了这条规则。

为 PyTorch 提供足够的共享内存

Docker 默认将 /dev/shm 限制为 64 MB。PyTorch DataLoader 的 worker 进程和 NCCL 都依赖共享内存,因此训练会失败,并报出“bus error”或“insufficient shared memory (shm)”消息。请共享主机的 IPC 命名空间,或者提高该限制(将 YY.MM 替换为当前的标签):

# share the host IPC namespace, as NVIDIA recommends for its PyTorch images
docker run --rm -it --gpus all --ipc=host \
  --ulimit memlock=-1 --ulimit stack=67108864 \
  -v /data:/data nvcr.io/nvidia/pytorch:YY.MM-py3

# or keep IPC isolated with a larger /dev/shm
docker run --rm -it --gpus all --shm-size=16g \
  -v /data:/data nvcr.io/nvidia/pytorch:YY.MM-py3

在容器内,df -h /dev/shm 会显示可用空间。在 Compose 中,请使用 ipc: host 或 shm_size: "16gb"。vLLM 镜像也需要同样的处理,参见用 vLLM 提供大语言模型(LLM)推理服务。

AMD GPU:ROCm 中的对应做法

docker run --rm --device=/dev/kfd --device=/dev/dri \
  --group-add video --ipc=host \
  rocm/pytorch:latest \
  python3 -c "import torch; print(torch.cuda.device_count())"

在 MI355X 服务器上,这条命令会输出 8。运行 ROCm 容器的标准方式是传入设备文件,而不是使用 --gpus:/dev/kfd 是计算接口,/dev/dri 中则是 GPU 设备节点。要让容器只使用部分 GPU,请添加 -e HIP_VISIBLE_DEVICES=0,1。其余内容请参阅 ROCm 配置。

故障排查

  • could not select device driver "" with capabilities: [[gpu]] 或 unknown or invalid runtime name: nvidia。Docker 尚未配置 NVIDIA 运行时。请运行 sudo nvidia-ctk runtime configure --runtime=docker,然后运行 sudo systemctl restart docker。
  • unsatisfied condition: cuda>=X.Y. 该镜像需要更新的驱动。请改用较旧的镜像标签,或在控制台提交工单咨询驱动问题。
  • 连接 Docker 守护进程套接字时出现 permission denied。请使用 sudo,或者将您的用户加入 docker 组,然后重新登录。

问题仍未解决?

请在控制台提交工单,写明服务器、您运行了什么以及错误输出(如有)。工程师 7×24 小时答复。

提交工单

登录 FullGPU

管理您的 GPU 服务器、余额和账单。

首次使用 FullGPU? 创建账户