K8s集群vGPU故障排查:从Pod调度失败到驱动验证
K8s集群里vGPU出问题,通常表现为Pod一直Pending、调度器报Insufficient nvidia.com/gpu、或者容器起来了但nvidia-smi报错。
这类故障大多不在K8s本身,而在节点驱动、设备插件和资源声明这三层。
下面按“先定位现象,再逐层验证”的顺序展开,命令可直接在节点或跳板机上执行。
先确认故障停在哪一层
不要一上来就重启kubelet。
先看Pod状态和调度事件:
kubectl describe pod -n
重点看Events区域。
如果出现0/3 nodes are available: 3 Insufficient nvidia.com/gpu,说明调度器认为节点没有可用的vGPU资源,问题在资源上报环节。
如果Pod已经Running但业务报CUDA错误,说明调度通过但运行时环境有问题。
在目标节点上直接跑:
nvidia-smi
kubectl get node -o json | grep -A5 nvidia
前者验证宿主机驱动是否正常,后者验证K8s是否识别到GPU资源。
两者结果不一致,基本可以锁定是device plugin的问题。
节点侧:驱动与设备插件检查
宿主机驱动是否可用
nvidia-smi能正常输出GPU列表和驱动版本,说明内核模块已加载。
如果命令不存在或报NVIDIA-SMI has failed,先处理驱动,不要继续查K8s。
确认驱动版本:
cat /proc/driver/nvidia/version
记录版本号,后面要和device plugin、CUDA镜像做匹配。
device plugin是否正常运行
NVIDIA官方推荐用DaemonSet方式部署。
检查:
kubectl get pods -n kube-system | grep nvidia
kubectl logs -n kube-system
常见日志报错包括Failed to initialize NVML: Driver/library version mismatch(驱动与库版本不一致)和no devices found(vGPU未正确透传或未授权)。
如果是vGPU场景,还要确认宿主机已加载vGPU内核模块并完成授权,这部分依赖具体的虚拟化平台配置。
节点资源是否上报
kubectl describe node | grep -A10 Capacity
正常情况下应看到nvidia.com/gpu: 1或对应vGPU数量。
如果没有这一行,说明device plugin没有成功注册资源,回到上一步看日志。
Pod侧:资源声明与镜像匹配
调度失败有时是YAML写错了。
检查Pod的resources字段:
resources:
limits:
nvidia.com/gpu: 1
注意三点:vGPU资源名必须是集群中实际注册的名称,不同插件可能用nvidia.com/gpu或自定义名称;
requests和limits建议保持一致,否则可能被调度到没有vGPU的节点;
不要在limits里写小数,K8s的扩展资源不支持。
镜像方面,容器内需要能访问NVIDIA驱动库。
如果镜像里没有nvidia-smi,可以临时进入容器验证:
kubectl exec -it -- nvidia-smi
报command not found不一定是故障,
但报Failed to initialize NVML就说明容器运行时没有正确挂载驱动,
需要检查容器运行时是否配置了NVIDIA runtime。
常见报错与处理方向
Pod一直Pending,
事件显示Insufficient nvidia.com/gpu:
优先检查device plugin Pod是否Running、
节点Capacity是否有GPU资源、
Pod的resources名称是否匹配。
容器内nvidia-smi报NVML初始化失败:
检查容器运行时(containerd或Docker)是否将NVIDIA设为默认runtime,
以及节点驱动版本是否与镜像内CUDA版本兼容。
device plugin日志报驱动版本不匹配:宿主机升级驱动后未重启kubelet或device plugin,重建DaemonSet Pod通常可解决。
vGPU数量对不上:确认虚拟化平台分配的vGPU实例数与节点实际识别数一致,部分平台需要额外安装guest驱动。
验证排错是否生效
完成修复后,用一个小测试Pod验证整条链路:
kubectl run gpu-test --image=nvidia/cuda:12.0-base --restart=Never \
--limits=nvidia.com/gpu=1 -- nvidia-smi
等待Pod完成,查看日志:
kubectl logs gpu-test
能正常输出GPU型号和驱动版本,说明调度、设备插件、容器运行时三层都通了。
清理测试Pod:
kubectl delete pod gpu-test
如果仍然失败,回到kubectl describe pod gpu-test看事件,按前面的分层顺序重新排查。
几个容易踩的坑
升级GPU驱动后没有重启节点或重建device plugin,导致旧进程仍持有旧版本库;
在values.yaml里改了资源名称但忘记同步更新业务YAML;
vGPU授权过期后宿主机nvidia-smi可能仍能显示设备,但容器内无法使用;
多节点集群中只有部分节点装了驱动,调度器不会自动避开,需要给节点打taint或label做约束。
排查时保持一个原则:先确认宿主机能识别GPU,再确认K8s能上报资源,最后确认容器能访问设备。
任何一层断了,后面的操作都不会生效。