K8s 部署 GPU 推理 Pod 时如果报“显存不足”,先不要把“物理卡可用”当作不会被调度的依据。K8s 的调度和资源管理按整卡数量计算,不感知显存;所以“卡空闲”和“Pod 能启动后不爆显存”是两回事。需要先确认报错出现在调度阶段还是容器运行阶段,再决定改配额还是改显存隔离策略。
通常,K8s 只按 GPU 卡的数量来分配资源,不对显存做隔离。显存不足但物理卡有空闲,多半是 Pod 的资源声明不完整、命名空间下的 ResourceQuota/LimitRange 没把 GPU 扩展资源算进去,或者设备插件没有真正分配可用显存。排查时先看 Pod 事件和资源描述,再核对 nvidia.com/gpu 的 request/limit 与配额。
先分清是调度失败还是运行期 OOM
用 kubectl describe pod <pod-name> -n <namespace> 查看 Events 和容器状态。如果 Pod 停在 Pending,说明调度阶段没有可用节点,通常是申请数量超过了节点可分配额度或命名空间配额不足。如果 Pod 已经 Running,但容器日志出现 CUDA error: out of memory,那是容器启动后进程申请显存失败,和 K8s 配额可能没有直接关系。
物理卡显示“空闲”时,还要注意宿主机上可能已经存在占用显存的进程,K8s 的 GPU 资源只统计整卡数量,不会统计显存占用,所以多个 Pod 调度到同一张卡上并不冲突,但实际运行时会互相踩踏。
调整 ResourceQuota 与 LimitRange
如果报错发生在调度阶段,先检查命名空间的配额。执行 kubectl get quota -n <namespace> -o yaml 查看是否限制 nvidia.com/gpu。若配额中的 hard 数值小于 Pod 请求的数量,即使节点有剩余 GPU,调度器也不会放置 Pod。
示例:为命名空间调整 GPU 配额上限:
apiVersion: v1
kind: ResourceQuota
metadata:
name: gpu-quota
namespace: inference
spec:
hard:
nvidia.com/gpu: 4
同时检查 LimitRange 是否对未显式声明资源的容器注入了默认 GPU 值。若默认值比预期高,会直接放大每个副本的显存需求,导致“显存不足”的假象。示例调整默认请求与上限:
apiVersion: v1
kind: LimitRange
metadata:
name: gpu-lr
namespace: inference
spec:
limits:
- default:
nvidia.com/gpu: 1
defaultRequest:
nvidia.com/gpu: 1
type: Container
修改后执行 kubectl apply -f <文件>,再用 kubectl get limitrange -n <namespace> 确认默认值已生效。
核对 Pod 资源声明
GPU 是排他型扩展资源,通常要求 requests 和 limits 数值一致,且只能写整数。若 Deployment 里只写了 requests,没有写 limits,device plugin 可能不会注入 GPU 环境变量;若只写 limits,调度时可能按 requests 为 0 处理,导致多个副本叠加到同一张卡。建议统一写成:
resources:
requests:
nvidia.com/gpu: 1
limits:
nvidia.com/gpu: 1
如果确实需要按显存大小切分,原生 K8s 的扩展资源不支持小数,需要借助 NVIDIA MIG 或 vGPU 方案。启用 MIG 后,nvidia-device-plugin 会把 MIG 实例注册为独立资源,此时 Pod 请求的资源名可能从 nvidia.com/gpu 变为不同标识的实例资源,要结合插件配置确认。
验证和处理顺序
- 用
kubectl describe node | grep -i 'nvidia.com/gpu'确认节点 capacity 和 allocatable 中有 GPU 扩展资源。 - 用
kubectl describe pod <pod-name> -n <namespace>查看 Resources.Requests 是否等于预期值,Events 是否有 Insufficient nvidia.com/gpu。 - 进入 Pod 执行
nvidia-smi -L,确认容器内可见的 GPU 数量和实例;同时在宿主机执行nvidia-smi `--query-gpu`=memory.used,memory.total `--format`=csv对比实际显存占用。 - 若涉及命名空间配额调整,修改后先 apply ResourceQuota 或 LimitRange,再更新 Deployment 的资源声明,最后删除旧 Pod 重新调度。
调整配额只是让 K8s 允许放置更多 GPU Pod;如果显存不足源于多进程抢占,还需要通过 MIG、MPS 或显存配额类插件做隔离。这类方案需要结合驱动、容器运行时和 device plugin 版本确认,不建议直接照搬某一种固定配置。