在 AI 推理、深度学习训练和视频编解码场景中,Docker 能隔离应用依赖,但普通容器不会自动获得 NVIDIA GPU 访问权限。完整链路涉及宿主机显卡驱动、Docker Engine、NVIDIA Container Toolkit、容器运行时和 CUDA 镜像;任何一层异常,都可能导致容器看不到 GPU、启动时报错或任务意外落到 CPU。本文给出一套从资源分配到故障定位的实用流程。🧭
一、先理解 GPU 进入容器的链路
NVIDIA Container Toolkit 并不是把显卡驱动完整安装进容器,而是在容器启动时,根据参数挂载必要的设备节点和驱动库。因此,宿主机驱动必须先正常工作,容器镜像中的 CUDA 用户态组件还要与宿主机驱动兼容。Toolkit 的作用、支持的容器引擎及整体架构可参考 来源链接 Container Toolkit 官方文档。
排查时应严格遵循“宿主机 → Toolkit → Docker Runtime → 测试镜像 → 业务应用”的顺序。不要一看到 CUDA 报错就反复更换镜像,否则很容易掩盖真正的问题。
二、验证宿主机基础环境
第一步是在宿主机执行以下命令:
nvidia-smi
docker version
docker info
如果 nvidia-smi 无法列出 GPU、驱动版本和显存信息,应优先修复驱动,而不是继续调整 Docker。若 Docker 服务本身异常,可执行 systemctl status docker 和 journalctl -u docker --no-pager -n 100 查看守护进程日志。生产服务器升级驱动前,建议记录内核、驱动与业务镜像版本,并准备回滚方案。⚠️
三、安装并配置 NVIDIA Container Toolkit
应按照当前 Linux 发行版对应的步骤添加 NVIDIA 软件源并安装 Toolkit,避免直接复制年代较久的第三方命令。安装方法以 来源链接 为准。安装完成后,可使用以下方式让工具自动修改 Docker Runtime 配置:
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
随后检查运行时和工具是否可用:
nvidia-ctk --version
nvidia-container-cli --version
docker info
如果执行命令后 Docker 无法启动,应检查 /etc/docker/daemon.json 是否存在 JSON 语法错误或与原有 runtime 配置冲突。可先运行 dockerd --validate --config-file=/etc/docker/daemon.json 验证配置,再重启服务。
四、按需分配 GPU 资源
验证全部 GPU 最常用的命令如下,其中镜像标签应根据实际兼容需求选择,不要在长期运行环境中依赖含义可能变化的标签:
docker run --rm --gpus all nvidia/cuda:12.9.0-base-ubuntu22.04 nvidia-smi
多卡主机不应默认把全部 GPU 暴露给每个容器。若只分配编号为 0 的设备,可执行:
docker run --rm --gpus device=0 nvidia/cuda:12.9.0-base-ubuntu22.04 nvidia-smi
需要多张指定显卡时,可以使用 --gpus '"device=0,2"'。在自动化脚本中,更推荐使用 nvidia-smi -L 获取 GPU UUID,再按 UUID 分配,避免设备编号在重启或硬件调整后产生歧义。Docker 的 GPU 参数、资源约束及前置条件可查看 Docker GPU 资源约束说明。🎯
需要注意,限制“可见 GPU”不等于严格限制显存容量。普通 GPU 通常仍由同一卡上的进程竞争显存和算力;如需更强的硬件级隔离,应评估显卡是否支持 MIG,并结合任务队列、监控和并发控制实施。
五、Docker Compose 的分配方式
Compose 可以在设备预留中声明 NVIDIA 驱动、GPU 数量或设备 ID,并必须设置 capabilities: [gpu]。其中 count 与 device_ids 不能同时使用。具体字段和示例可参考 Docker Compose GPU 支持文档。
deploy:
resources:
reservations:
devices:
- driver: nvidia
device_ids: ['0']
capabilities: [gpu]
修改后可执行 docker compose config 检查最终合并结果,再运行 docker compose up,避免缩进、变量替换或覆盖文件导致配置没有生效。
六、常见故障的定位方法
1. 报错“could not select device driver”
通常表示 Toolkit 未安装、NVIDIA Runtime 未正确注册,或 Docker 尚未重新加载配置。依次检查 nvidia-ctk --version、docker info 和 Docker 服务日志,并重新执行 runtime configure。
2. 容器内找不到 nvidia-smi
先使用 NVIDIA CUDA 基础镜像复测。如果官方测试镜像正常,而业务镜像失败,问题多半位于业务镜像、环境变量或启动脚本;如果测试镜像也失败,则返回宿主机驱动与 Runtime 层检查。
3. 出现 NVML 或驱动通信错误
常见诱因包括宿主机驱动失效、内核升级后模块未正确加载,或系统更新驱动后仍运行旧容器。可比较宿主机与容器内的 nvidia-smi 结果,并检查 lsmod | grep nvidia、内核日志及是否需要维护窗口重启。
4. apt 更新提示 Signed-By 冲突
这通常是旧版 NVIDIA 软件源文件与新配置重复。可执行 grep -R "nvidia.github.io" /etc/apt/sources.list.d/ 定位重复条目,确认后删除过时配置。处理方式可参考 NVIDIA 官方故障排查指南。
5. 仍无法确定根因
可在 /etc/nvidia-container-runtime/config.toml 中启用 debug 日志,重新执行最小化测试命令并收集输出。同时保存 Docker 日志、Toolkit 版本、驱动信息、镜像完整标签和启动参数,便于复现。不要在日志中公开令牌、私有仓库凭据或业务数据。🔍
七、生产环境检查清单
- 宿主机 nvidia-smi 可以稳定识别全部 GPU。
- Toolkit、Docker 及驱动版本均有记录,配置文件已备份。
- 官方 CUDA 测试镜像能够正常访问指定 GPU。
- 每个容器仅暴露业务所需设备,并同时设置 CPU、内存等限制。
- 通过宿主机 nvidia-smi、应用日志和监控系统核对显存、利用率及进程。
- 升级驱动、Toolkit 或 Docker 前先在非生产节点验证,并保留回滚路径。
总结
Docker GPU 故障最有效的处理方式不是“不断重装”,而是按层验证:先确认宿主机驱动,再检查 NVIDIA Container Toolkit 和 Docker Runtime,随后使用官方 CUDA 镜像完成最小化测试,最后定位业务镜像。资源分配方面,应优先指定设备 ID 或 UUID,避免无条件使用全部 GPU;对于显存和算力隔离,则需要结合硬件能力与调度策略。按照这条链路执行,大多数 GPU 不可见、Runtime 未注册和驱动通信异常都能得到清晰定位。✅