一、为什么 Kubernetes 需要管理 GPU?
1.1 业务驱动:AI/ML 工作负载的爆发
随着深度学习、大语言模型(LLM)等 AI 技术的普及,GPU 已成为关键的基础设施资源。典型的 GPU 应用场景包括:
- AI 训练:PyTorch、TensorFlow 等框架需要 GPU 加速矩阵运算
- AI 推理:在线服务需要低延迟的 GPU 计算能力
- 图形渲染:3D 渲染、视频编解码等任务依赖 GPU 的并行处理能力
1.2 问题驱动:GPU 昂贵且难以管理
高端 GPU(如 NVIDIA A100)单卡成本可达数万美元,但实际使用中存在严重的资源浪费:
- 分配了但未使用:数据科学家申请 4 张 GPU,训练 2 小时后离开工位,GPU 被独占但闲置
- 无法共享:默认情况下,一张 GPU 只能被一个 Pod 使用,导致小模型"杀鸡用牛刀"
- 调度黑盒:K8s 原生调度器无法感知 GPU 拓扑、实时利用率等信息
1.3 K8s 原生能力的局限
CPU 和内存是 K8s 的"一等公民"——可以被切分、超卖、时间片调度。但 GPU 在金丝雀版本中遇到了尴尬:
- 不能被 kube-scheduler 原生切分
- 不能像 CPU 一样时间片抢占
- 不能像内存一样 swap
因此 K8s 早期的态度是——“GPU?我不懂,你自己搞。” 这也催生了 Device Plugin 机制的诞生。
二、K8s GPU 管理的核心架构
2.1 整体架构分层
基于 NVIDIA 官方参考架构和社区实践,K8s GPU 管理可以分为以下几个层次:
┌─────────────────────────────────────────────────────────────┐
│ 应用层 (Inference Serving) │
│ Triton / Dynamo / vLLM / TensorFlow │
├─────────────────────────────────────────────────────────────┤
│ 编排层 (Orchestration) │
│ KAI Scheduler / Volcano / Default Scheduler │
├─────────────────────────────────────────────────────────────┤
│ 资源抽象层 (Resource Mgmt) │
│ Device Plugin / DRA Driver / GPU Manager │
├─────────────────────────────────────────────────────────────┤
│ 运行时层 (Runtime) │
│ NVIDIA Container Toolkit / containerd / Kata │
├─────────────────────────────────────────────────────────────┤
│ 基础设施层 (Infrastructure) │
│ GPU Drivers / DCGM / NVLink / RDMA │
└─────────────────────────────────────────────────────────────┘2.2 Device Plugin:GPU 进入 K8s 的"通行证"
Device Plugin 是 K8s 提供的扩展机制,让厂商可以自定义资源类型的发现和上报。NVIDIA 的 k8s-device-plugin 实现了:
- 探测节点上的 GPU:调用
nvidia-smi获取 GPU 数量 - 向 kubelet 注册资源:上报资源名为
nvidia.com/gpu - 响应分配请求:kubelet 请求分配 GPU 时,返回设备路径
# Device Plugin 以 DaemonSet 方式运行
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: nvidia-device-plugin
spec:
template:
spec:
containers:
- image: nvidia/k8s-device-plugin:v0.12.0
name: nvidia-device-plugin
securityContext:
privileged: true # 需要访问 /dev/nvidia* 2.3 调度器演进:从 Default Scheduler 到 KAI/Volcano
默认调度器的局限:
- 只检查"分配量",不检查"实际使用量"
- 不支持 Gang Scheduling(多 Pod 同时调度)
- 无公平共享机制
KAI Scheduler(已捐给 CNCF Sandbox)填补了这些空白:
- Gang Scheduling:确保分布式训练的所有 Pod 同时被调度
- Dominant Resource Fairness:多团队间公平分配 GPU
- 队列管理:支持分级队列和优先级
Volcano(国内广泛使用):
- 支持 GPU 亲和性调度
- Binpack 堆叠调度优化利用率
三、Pod 如何使用 GPU?
3.1 标准用法:通过 resources.limits 声明
Pod 通过标准的 K8s 资源声明方式申请 GPU:
apiVersion: v1
kind: Pod
metadata:
name: gpu-training-job
spec:
containers:
- name: trainer
image: pytorch/pytorch:latest
command: ["python", "train.py"]
resources:
limits:
nvidia.com/gpu: 1 # 申请 1 张 GPU关键注意事项:
- GPU 只能写在
limits中,不能只写requests - GPU 不能被超卖,
requests和limits必须保持一致 禁止以下非标操作:
docker run --gpus all- 手动设置
NVIDIA_VISIBLE_DEVICES环境变量 - 容器内挂载
/dev/nvidia*设备
违规范例:
# ❌ 错误:不应该这样做
env:
- name: NVIDIA_VISIBLE_DEVICES
value: "all"3.2 GPU 共享:从整卡独占到精细切分
| 模式 | 配置方式 | 适用场景 |
|---|---|---|
| 整卡独占 | nvidia.com/gpu: 1 | 大模型训练 |
| MIG 硬隔离 | nvidia.com/mig-1g.5gb | A100/H100 多租户 |
| 时间片共享 | Device Plugin 配置 | 推理高并发 |
| 小数共享 | nvidia.com/gpu: 0.2 | 轻量推理 |
MIG 示例(A100/H100):
resources:
limits:
nvidia.com/mig-1g.5gb: 1 # 申请 1/7 的 GPU3.3 节点亲和性:确保 Pod 落到有 GPU 的节点
创建 GPU 节点后,系统会自动添加标签:
# 查看节点的 GPU 标签
kubectl get node -L accelerator
# 输出示例
NAME STATUS ACCELERATOR
node-1 Ready nvidia-t4Pod 中通过 nodeSelector 指定需要的 GPU 类型:
spec:
nodeSelector:
accelerator: nvidia-t4 # 必须匹配节点标签四、完整的数据流:从 Pod 创建到 GPU 使用
下面用一张图说明完整流程:
1. Pod 创建
│
▼
2. API Server 接收请求
│ Pod.spec.containers[].resources.limits["nvidia.com/gpu"] = 1
▼
3. Scheduler 调度
│ - 检查节点可分配资源
│ - 找到有足够 GPU 的节点
▼
4. kubelet (节点上)
│ - 调用 Device Plugin 的 Allocate() RPC
│ - Device Plugin 返回设备路径: /dev/nvidia0
▼
5. 容器运行时 (containerd/docker)
│ - NVIDIA Container Toolkit 注入环境变量
│ - 设置 NVIDIA_VISIBLE_DEVICES=GPU-xxx
▼
6. 容器启动
│ - GPU 设备挂载到容器
│ - 应用调用 CUDA API 使用 GPU
▼
7. 可观测性
- DCGM Exporter 采集指标
- Prometheus 存储,Grafana 展示五、高级调度:闲置 GPU 回收
5.1 问题场景
默认调度器的一大痛点:Pod 申请了 GPU 但利用率很低,其他任务却因资源不足而排队。
实际情况:
Node 有 8 张 GPU
Pod A 申请了 4 张,但只用 20%
Pod B 需要 2 张,但一直 pending5.2 解决方案:利用率感知抢占
HPE 贡献的开源方案 ReclaimIdleResource 调度插件:
核心逻辑(在 PostFilter 阶段执行):
- 查询 Prometheus 中的 DCGM GPU 利用率指标
判断候选 Pod 是否满足被抢占条件:
- 优先级低于抢占者
- 运行时间超过"容忍期"(如 1 小时)
- GPU 利用率低于阈值(如 10%)
- 优先抢占最"空闲"的 Pod
通过 PriorityClass 注解配置策略:
kind: PriorityClass
metadata:
name: batch-workload
annotations:
# 只有优先级 ≥10000 的 Pod 可以抢占
reclaim-idle-resource.scheduling.x-k8s.io/minimum-preemptable-priority: "10000"
# 调度后 1 小时内不可被抢占(保护刚启动的任务)
reclaim-idle-resource.scheduling.x-k8s.io/toleration-seconds: "3600"
# GPU 使用率低于 10% 且持续 1 小时,才可被抢占
reclaim-idle-resource.scheduling.x-k8s.io/resource-idle-usage-threshold: "10.0"
value: 8000六、可观测性:DCGM
6.1 核心指标
NVIDIA DCGM (Data Center GPU Manager) 提供 GPU 的"体检报告":
| 指标 | 含义 | 告警建议 |
|---|---|---|
DCGM_FI_DEV_GPU_UTIL | GPU 计算利用率 | <10% 持续 1h → 资源闲置 |
DCGM_FI_DEV_FB_USED | 显存使用量 | >90% → 可能 OOM |
DCGM_FI_DEV_POWER_USAGE | 功耗 | 异常波动 → 硬件问题 |
node_gpu_temperature_celsius | GPU 温度 | >85°C → 触发冷却 |
6.2 部署架构
# DCGM Exporter 作为 DaemonSet 部署
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: dcgm-exporter
spec:
template:
spec:
containers:
- name: dcgm-exporter
image: nvidia/dcgm-exporter:latest
securityContext:
privileged: true配合 Prometheus + Grafana 即可构建 GPU 监控大盘。
七、面试高频 QA
Q1:K8s 调度 GPU 的核心流程是什么?
A:Pod 在 resources.limits 中声明 nvidia.com/gpu: 1。调度器看到这个资源请求后,根据 Device Plugin 上报的节点 GPU 数量,将 Pod 绑定到有足够资源的节点。最后 kubelet 通过 NVIDIA Container Toolkit 将 GPU 设备挂载进容器。关键点:GPU 只能写在 limits 中,不能超卖。
Q2:GPU 整卡调度浪费严重,如何解决?
A:三种主要方式:1) MIG:A100/H100 支持硬件级切分;2) 时间片共享:多个 Pod 分时使用;3) 小数 GPU:nvidia.com/gpu: 0.2 表示 20% 算力。需要 Device Plugin 和调度器的配合。
Q3:Pod 申请了 GPU 但利用率很低,怎么回收?
A:默认调度器不支持。可以使用自定义调度插件(如 ReclaimIdleResource),通过查询 Prometheus 中的 DCGM 利用率指标,判断哪些 Pod 长期空闲并在优先级允许时进行抢占。
Q4:KAI Scheduler 解决了什么问题?
A:KAI 提供了原生调度器缺失的 AI 工作负载语义:Gang Scheduling(分布式训练的所有 Pod 同时调度)、Fair Sharing(多团队公平分配)、拓扑感知调度等。已捐给 CNCF 作为 Sandbox 项目。
Q5:DRA (Dynamic Resource Allocation) 是什么?
A:K8s 新一代资源分配机制,相比 Device Plugin 更灵活。NVIDIA 已将其 DRA Driver 捐给 CNCF。DRA 支持属性感知调度(如根据 GPU 型号、MIG 配置等),而 Device Plugin 只能上报整数数量。
八、总结
- 统一入口:所有 GPU 应用必须通过 K8s 调度,禁止节点上直接
docker run --gpus all - 节点分池:训练节点、推理节点、MIG 节点分开,用
nodeSelector隔离 - 优先级机制:用 PriorityClass 区分离线训练和在线推理,确保 SLA
- 监控先行:部署 DCGM + Prometheus + Grafana,可视化 GPU 使用情况
根据场景选择切分方式:
- 大模型训练 → 整卡独占
- 多租户 → MIG 硬隔离
- 高并发推理 → 时间片共享