速查·3.X GPU 容器排障补遗(一) 正文 3.3 的排障地图覆盖了"没传 --gpus、驱动太老、看错卡、MPS/MIG 不生效"四大主故障。本条是补充现场:报错更怪、因果链更长,但每一类都在真实环境里反复出现。 故障一:nvidia-smi 正常,torch.cuda.isavailable() 却是 False 定位:卡在、驱动在,问题出在 Python 侧。容器里先跑: 归因:① torch 装成了 CPU 版(最常见, 输出 None 即是);② torch 编译时绑定的 CUDA 版本高于驱动支持的上限。 处置:CPU 版就按镜像 CUDA 版本重装官方 wheel;版本超限就换镜像或升驱动。别急着怀疑 GPU,先确认 torch 本身。
正文 3.3 的排障地图覆盖了"没传 --gpus、驱动太老、看错卡、MPS/MIG 不生效"四大主故障。本条是补充现场:报错更怪、因果链更长,但每一类都在真实环境里反复出现。
定位:卡在、驱动在,问题出在 Python 侧。容器里先跑:
python -c "import torch; print(torch.version.cuda, torch.cuda.device_count())"
归因:① torch 装成了 CPU 版(最常见,torch.version.cuda 输出 None 即是);② torch 编译时绑定的 CUDA 版本高于驱动支持的上限。
处置:CPU 版就按镜像 CUDA 版本重装官方 wheel;版本超限就换镜像或升驱动。别急着怀疑 GPU,先确认 torch 本身。
现象:宿主机 nvidia-smi 正常,容器里统一报 NVML 初始化失败。
归因:驱动升级重载了内核模块,但 nvidia-container-toolkit 注入容器的还是旧版用户态组件;有时 toolkit 自身也要随新驱动升级。
处置:宿主机上 sudo systemctl restart docker 让 toolkit 重新挂载;若报 driver/library version mismatch,说明内核模块与用户态版本不一致,先确认没有进程占用模块再彻底重启。运维约定:升驱动属于变更窗口操作,完成后必跑容器冒烟测试。
归因:内核里加载的 nvidia 模块版本与用户态库不一致——典型发生于"运行中升级驱动"之后。
处置:lsof /dev/nvidia* 或 fuser -v /dev/nvidia* 找出仍在占用 GPU 的进程,全部停止后卸载并重载 nvidia 模块,或直接重启。有进程占着模块时卸载不会成功。
现象:nvidia-smi 显示显存几乎占满,进程列表却是空的。
归因:进程在容器里跑,宿主机的 nvidia-smi 在容器 PID 命名空间外看不全;或容器异常退出后留下了僵尸进程。
处置:宿主机上 fuser -v /dev/nvidia* 按设备文件反查 PID,杀掉后显存立即释放。长期对策:容器加 --init 正确回收僵尸进程,训练脚本里注册 SIGTERM 处理器做优雅退出。
现象:明明指定了 2、3 号卡,任务却跑在 0 号卡上。
归因:--gpus '"device=2,3"' 决定容器能看到哪些卡,容器内会重新编号为 0、1;容器里再设 CUDA_VISIBLE_DEVICES=2,3 是在"容器可见集合"里挑——此时 2、3 根本不存在,实际就落到了 0 号。
处置:两选一,别叠用。要么只用 --gpus 在宿主机侧选卡;要么 --gpus all + 容器内 CUDA_VISIBLE_DEVICES 选卡。混用时必须想清楚编号属于哪个命名空间。
归因:WSL2 集成模式下,GPU 支持依赖 Windows 驱动与 WSL2 内核的配合;Docker Desktop 版本旧,或该 WSL 发行版未启用集成。
处置:① Windows 侧装最新 NVIDIA 驱动(WSL2 内不需要也不应该单独装驱动);② Docker Desktop 设置里确认该发行版已启用 integration;③ wsl --update 升级后再试。仍不行时,在 WSL2 发行版内直接安装原生 Docker(绕过 Docker Desktop)通常可解。
先分清问题在哪一层:驱动层(宿主机 nvidia-smi)→ 透传层(docker run 报错)→ 库层(容器内 nvidia-smi)→ 框架层(torch 等报错)。一层一层往下验证——别在框架报错时去重装驱动,也别在驱动都坏了时调框架参数。
详细原理见正文第三章 3.1「NVIDIA Container Runtime 的调用链剖析」与 3.2「显存、算力与设备视图的隔离边界」。