一、为什么 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 实现了:

  1. 探测节点上的 GPU:调用 nvidia-smi 获取 GPU 数量
  2. 向 kubelet 注册资源:上报资源名为 nvidia.com/gpu
  3. 响应分配请求: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

关键注意事项

  1. GPU 只能写在 limits,不能只写 requests
  2. GPU 不能被超卖,requestslimits 必须保持一致
  3. 禁止以下非标操作:

    • 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.5gbA100/H100 多租户
时间片共享Device Plugin 配置推理高并发
小数共享nvidia.com/gpu: 0.2轻量推理

MIG 示例(A100/H100):

resources:
  limits:
    nvidia.com/mig-1g.5gb: 1  # 申请 1/7 的 GPU

3.3 节点亲和性:确保 Pod 落到有 GPU 的节点

创建 GPU 节点后,系统会自动添加标签:

# 查看节点的 GPU 标签
kubectl get node -L accelerator

# 输出示例
NAME           STATUS   ACCELERATOR
node-1         Ready    nvidia-t4

Pod 中通过 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 张,但一直 pending

5.2 解决方案:利用率感知抢占

HPE 贡献的开源方案 ReclaimIdleResource 调度插件:

核心逻辑(在 PostFilter 阶段执行):

  1. 查询 Prometheus 中的 DCGM GPU 利用率指标
  2. 判断候选 Pod 是否满足被抢占条件:

    • 优先级低于抢占者
    • 运行时间超过"容忍期"(如 1 小时)
    • GPU 利用率低于阈值(如 10%)
  3. 优先抢占最"空闲"的 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_UTILGPU 计算利用率<10% 持续 1h → 资源闲置
DCGM_FI_DEV_FB_USED显存使用量>90% → 可能 OOM
DCGM_FI_DEV_POWER_USAGE功耗异常波动 → 硬件问题
node_gpu_temperature_celsiusGPU 温度>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) 小数 GPUnvidia.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 只能上报整数数量。


八、总结

  1. 统一入口:所有 GPU 应用必须通过 K8s 调度,禁止节点上直接 docker run --gpus all
  2. 节点分池:训练节点、推理节点、MIG 节点分开,用 nodeSelector 隔离
  3. 优先级机制:用 PriorityClass 区分离线训练和在线推理,确保 SLA
  4. 监控先行:部署 DCGM + Prometheus + Grafana,可视化 GPU 使用情况
  5. 根据场景选择切分方式

    • 大模型训练 → 整卡独占
    • 多租户 → MIG 硬隔离
    • 高并发推理 → 时间片共享
正文到此结束
最后修改:2026 年 05 月 13 日
如果觉得我的文章对你有用,请随意赞赏