GPU 调度的常见问题
在 K8s 上跑 GPU 任务,总会遇到各种调度问题。
这篇汇总常见问题和排查方法。
问题一:GPU 资源不显示
现象
kubectl describe node gpu-node | grep nvidia
# 什么都没有
排查步骤
1. 检查 Device Plugin
kubectl get pods -n kube-system | grep nvidia
没有运行?安装 NVIDIA Device Plugin:
kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/master/nvidia-device-plugin.yml
2. 检查 Device Plugin 日志
kubectl logs -n kube-system nvidia-device-plugin-xxxx
常见错误:
failed to initialize NVML: could not load NVML library
原因:节点上没装 NVIDIA 驱动或 Container Toolkit。
3. 检查节点驱动
# SSH 到节点
nvidia-smi
如果报错,说明驱动没装好。
4. 检查容器运行时
containerd 需要配置 nvidia runtime:
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia]
runtime_type = "io.containerd.runc.v2"
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.nvidia.options]
BinaryName = "/usr/bin/nvidia-container-runtime"
问题二:Pod 无法调度
现象
kubectl get pod gpu-pod
# Pending
kubectl describe pod gpu-pod
# 0/3 nodes are available: 3 Insufficient nvidia.com/gpu
排查步骤
1. 检查集群 GPU 总量
kubectl describe nodes | grep nvidia.com/gpu
2. 检查已使用量
kubectl get pods --all-namespaces -o json | \
jq '[.items[] | select(.spec.containers[].resources.limits["nvidia.com/gpu"]!=null)] | length'
3. 常见原因
- GPU 被其他 Pod 占满
- 请求的 GPU 数量超过单节点最大值
- nodeSelector 不匹配
4. 解决方案
# 等其他任务完成
# 或者调整请求的 GPU 数量
resources:
limits:
nvidia.com/gpu: 1 # 减少请求数量
问题三:容器内看不到 GPU
现象
# 容器内
nvidia-smi
# NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver
排查步骤
1. 检查环境变量
echo $NVIDIA_VISIBLE_DEVICES
应该是 all 或者具体的 GPU 编号(如 0,1)。
2. 检查设备挂载
ls -la /dev/nvidia*
应该能看到 /dev/nvidia0、/dev/nvidiactl 等。
3. 检查 Pod 配置
确认请求了 GPU:
resources:
limits:
nvidia.com/gpu: 1
4. 检查运行时配置
可能 nvidia runtime 没配置好。在节点上测试:
docker run --rm --gpus all nvidia/cuda:12.0-base nvidia-smi
问题四:GPU 利用率低
现象
nvidia-smi
# GPU 利用率只有 10-20%
原因分析
1. 推理场景
推理本身利用率就不高(带宽瓶颈)。
解决:增加 batch size,用 Continuous Batching。
2. 数据加载慢
CPU 加载数据跟不上 GPU 计算。
解决:
- 增加 DataLoader 的 num_workers
- 用更快的存储
- 数据预处理
3. 代码问题
训练循环有阻塞操作。
检查:
- 是否有不必要的
torch.cuda.synchronize() - 是否有 CPU 和 GPU 之间的频繁数据传输
4. 通信瓶颈
分布式训练时,通信时间太长。
检查 NCCL 带宽:
# 在节点上跑 nccl-tests
./all_reduce_perf -b 8 -e 128M -f 2 -g 8
问题五:OOM(显存不足)
现象
CUDA out of memory. Tried to allocate 2.00 GiB
排查步骤
1. 监控显存使用
nvidia-smi -l 1
# 或
watch -n 1 nvidia-smi
2. 常见原因和解决
| 原因 | 解决方案 |
|---|---|
| batch size 太大 | 减小 batch size |
| 模型太大 | 用量化、模型并行 |
| 显存泄漏 | 检查代码,及时释放 |
| KV Cache 太大 | 限制上下文长度 |
3. PyTorch 显存分析
import torch
print(torch.cuda.memory_summary())
4. 显存碎片
PyTorch 会缓存显存,可能导致碎片:
torch.cuda.empty_cache() # 清理缓存
问题六:多卡训练卡住
现象
训练开始后不动了,没有报错。
排查步骤
1. 检查是否 NCCL 问题
export NCCL_DEBUG=INFO
# 重新运行训练
看日志里有没有 NCCL 错误。
2. 常见原因
- 某张卡通信失败
- rank 配置错误
- 网络不通
3. 检查网络
# 检查 IB 状态
ibstat
# 检查 GPU P2P
nvidia-smi topo -m
4. 超时设置
export NCCL_TIMEOUT=1800 # 30 分钟
问题七:拓扑不优
现象
8 卡训练,但性能只有预期的一半。
原因
Pod 被调度到拓扑不好的 GPU 上。
nvidia-smi topo -m
# 可能的输出:
# GPU0 GPU1 GPU2 GPU3
# GPU0 X NV12 PHB SYS
# GPU1 NV12 X PHB SYS
# GPU2 PHB PHB X NV12
# GPU3 SYS SYS NV12 X
GPU0-GPU1 是 NVLink,GPU0-GPU3 是跨 CPU(SYS),带宽差很多。
解决
1. 用 Topology Aware Scheduling
NVIDIA 的 GPU Operator 支持拓扑感知调度。
2. 手动指定 GPU
env:
- name: CUDA_VISIBLE_DEVICES
value: "0,1,2,3" # 指定连续的 GPU
3. 用 Volcano 的 binpack 策略
让 Pod 尽量调度到同一节点。
问题八:Device Plugin 崩溃
现象
Device Plugin Pod 不断重启。
排查
kubectl logs -n kube-system nvidia-device-plugin-xxx --previous
常见原因
- NVML 库版本不匹配
- GPU 硬件故障
- 驱动版本问题
解决
- 更新驱动和 Device Plugin 版本
- 检查 GPU 健康状态:
nvidia-smi -q - 禁用故障 GPU
问题九:节点重启后 GPU 丢失
现象
节点重启后,GPU 不再显示。
原因
- 驱动没有开机自启
- NVIDIA 服务没启动
解决
# 检查驱动模块
lsmod | grep nvidia
# 如果没有,加载模块
sudo modprobe nvidia
# 设置开机自启
sudo systemctl enable nvidia-persistenced
调试工具汇总
| 工具 | 用途 |
|---|---|
| nvidia-smi | GPU 状态、进程、显存 |
| nvitop | 交互式 GPU 监控 |
| dcgmi | NVIDIA 数据中心 GPU 管理 |
| nvidia-smi topo | GPU 拓扑 |
| nccl-tests | 多卡通信带宽测试 |
| kubectl describe | K8s 资源状态 |
小结
GPU 调度问题速查表:
| 问题 | 关键排查点 |
|---|---|
| GPU 不显示 | Device Plugin、驱动、Container Toolkit |
| 无法调度 | 资源是否足够、nodeSelector |
| 容器内没 GPU | 环境变量、设备挂载、运行时配置 |
| 利用率低 | batch size、数据加载、通信 |
| OOM | 显存分析、batch size、量化 |
| 多卡卡住 | NCCL 日志、网络、超时 |
| 拓扑不优 | nvidia-smi topo、调度策略 |
核心方法:
- 看日志(kubectl logs、NCCL_DEBUG)
- 看状态(nvidia-smi、kubectl describe)
- 测试基础设施(nccl-tests、P2P 测试)
调度篇结束。下一部分讲工程化。