AI 算力基础设施深度系列(三):GPU 与异构算力——让 Kubernetes 驾驭每一块加速卡

AI 算力基础设施深度系列(三):GPU 与异构算力——让 Kubernetes 驾驭每一块加速卡

本文是《AI 算力基础设施深度系列》第 3 篇,共 6 篇。
系列目录:① 容器与 K8S 基础 → ② K8S 底层原理 → ③ GPU 与异构算力 → ④ AI 平台架构 → ⑤ 高性能网络与存储 → ⑥ 生产运维与成本优化

导语

一块 NVIDIA H100 的市场价约 $30,000。一个 8 卡 DGX H100 节点超过 $300,000。一个 1000 卡的训练集群,仅 GPU 成本就接近 400 万美元

而 Kubernetes 原生的 GPU 调度模型是这样的:

resources:
  limits:
    nvidia.com/gpu: 1   # "我要 1 块 GPU"——不管你的推理任务只需要 2GB 显存

一个推理任务只用了 2GB 显存,却独占一整块 80GB 的 A100。 这就像你只想在停车场停一辆自行车,却必须包下一整个车位。

NVIDIA 2024 年的调研显示,企业 GPU 集群的平均利用率不足 30%。在推理场景下更是低至 15%。每年有数以亿计的算力资源在空转中被浪费。

这篇文章要回答的核心问题是:Kubernetes 是怎么管理 GPU 的?为什么原生方案不够用?社区和厂商又是怎么填补这些缺口的?

我们将从 GPU 硬件基础开始,逐步深入到 Device Plugin 机制、NVIDIA 原生共享方案(MIG/MPS/Time-Slicing)、GPU 虚拟化中间件(HAMi)、下一代 DRA 框架,以及国产异构加速卡的统一管理。


一、GPU 硬件基础:理解你要管理的东西

在谈 GPU 调度之前,先理解 GPU 的硬件架构——这不是"可选的背景知识",而是理解所有后续技术决策的必要前提。

1.1 GPU 架构概览

以 NVIDIA H100 SXM5 为例:

┌─────────────────────────────── NVIDIA H100 ─────────────────────────────────┐
│                                                                              │
│  ┌──────────────────────── GPC (图形处理簇) ×8 ────────────────────────┐     │
│  │                                                                     │     │
│  │  ┌──── TPC ────┐  ┌──── TPC ────┐  ┌──── TPC ────┐               │     │
│  │  │  SM    SM   │  │  SM    SM   │  │  SM    SM   │  ...           │     │
│  │  │ 128   128  │  │ 128   128  │  │ 128   128  │               │     │
│  │  │ CUDA  CUDA │  │ CUDA  CUDA │  │ CUDA  CUDA │               │     │
│  │  │ Cores Cores│  │ Cores Cores│  │ Cores Cores│               │     │
│  │  └────────────┘  └────────────┘  └────────────┘               │     │
│  │                                                                     │     │
│  │  总计: 132 个 SM × 128 CUDA Cores = 16,896 CUDA Cores              │     │
│  │  + 528 Tensor Cores (4th Gen)                                       │     │
│  └─────────────────────────────────────────────────────────────────────┘     │
│                                                                              │
│  ┌─────────────── HBM3 (高带宽显存) ───────────────┐                        │
│  │  80GB (5 stacks × 16GB)                          │                        │
│  │  带宽: 3.35 TB/s                                 │                        │
│  └──────────────────────────────────────────────────┘                        │
│                                                                              │
│  ┌── L2 Cache ──┐  ┌── NVLink 4.0 ──┐  ┌── PCIe 5.0 ──┐                   │
│  │   50 MB      │  │  900 GB/s      │  │   128 GB/s    │                   │
│  └──────────────┘  │  (18 links)    │  │  (x16)        │                   │
│                     └────────────────┘  └───────────────┘                   │
└──────────────────────────────────────────────────────────────────────────────┘

关键组件解析

组件 作用 为什么重要
SM (Streaming Multiprocessor) GPU 的基本计算单元 算力隔离的基本粒度
CUDA Core 单精度浮点运算单元 通用计算的核心
Tensor Core 矩阵运算加速单元 AI 训练/推理的加速引擎
HBM (高带宽显存) GPU 专用显存 显存管理是 GPU 虚拟化的核心
NVLink GPU 间高速互联 拓扑感知调度的基础
L2 Cache 二级缓存 MIG 切分时每个实例有独立的 L2

1.2 GPU 互联拓扑

单机多卡场景下,GPU 之间的互联方式直接影响通信性能:

                    DGX H100 拓扑示例 (8x H100)

    ┌───────────────── NVSwitch 域 A ─────────────────┐
    │  ┌─────┐  ┌─────┐  ┌─────┐  ┌─────┐           │
    │  │GPU-0│←→│GPU-1│←→│GPU-2│←→│GPU-3│           │
    │  └─────┘  └─────┘  └─────┘  └─────┘           │
    │            NVLink 900 GB/s 全互联               │
    └─────────────────────────────────────────────────┘
                    │  PCIe 5.0 (128 GB/s)
    ┌───────────────── NVSwitch 域 B ─────────────────┐
    │  ┌─────┐  ┌─────┐  ┌─────┐  ┌─────┐           │
    │  │GPU-4│←→│GPU-5│←→│GPU-6│←→│GPU-7│           │
    │  └─────┘  └─────┘  └─────┘  └─────┘           │
    │            NVLink 900 GB/s 全互联               │
    └─────────────────────────────────────────────────┘

    性能差距:
    NVLink:   900 GB/s (同域)
    PCIe 5.0: 128 GB/s (跨域)
    差距:     ~7 倍

如果调度器不理解拓扑,把需要高频通信的两个 GPU 任务分配到不同 NVSwitch 域,训练性能会断崖式下降。 这就是为什么"拓扑感知调度"对 AI 场景至关重要。

1.3 CUDA 编程模型简述

理解 CUDA 编程模型有助于理解后续的 GPU 虚拟化原理:

                    CUDA 软件栈

    ┌─────────────────────────────┐
    │       用户应用程序            │
    │    (PyTorch / TensorFlow)   │
    ├─────────────────────────────┤
    │     CUDA Runtime API        │  ← cudaMalloc / cudaLaunchKernel
    │     (libcudart.so)          │     HAMi 在这一层做 API 劫持
    ├─────────────────────────────┤
    │     CUDA Driver API         │  ← cuMemAlloc / cuLaunchKernel
    │     (libcuda.so)            │
    ├─────────────────────────────┤
    │     GPU Driver              │
    │     (nvidia.ko)             │
    ├─────────────────────────────┤
    │     GPU 硬件                │
    └─────────────────────────────┘
  • CUDA Runtime API:高级接口,PyTorch 等框架主要调用这一层
  • CUDA Driver API:底层接口,直接操作驱动
  • GPU 虚拟化(如 HAMi)的核心就是在 Runtime API 层插入一个拦截层

二、Device Plugin 机制:K8S 管理 GPU 的基础

2.1 Device Plugin 工作原理

Device Plugin 是 Kubernetes 从 1.8 开始引入的设备管理框架。NVIDIA Device Plugin 实现了 GPU 在 K8S 中的发现、注册和分配。

                    Device Plugin 工作流

┌──────────┐                          ┌──────────────┐
│  kubelet │  ← gRPC Registration ──  │ NVIDIA Device│
│          │                          │ Plugin       │
│          │  ← ListAndWatch ──────── │ (DaemonSet)  │
│          │     (GPU 设备列表+状态)   │              │
│          │                          │              │
│          │  ── Allocate(GPU-0) ───► │              │
│          │  ◄─ 返回设备路径+环境变量  │              │
└──────────┘                          └──────────────┘

三个核心 gRPC 接口

service DevicePlugin {
    // 注册:向 kubelet 声明自己管理什么资源
    rpc GetDevicePluginOptions(Empty) returns (DevicePluginOptions);

    // 发现:持续上报设备列表和健康状态
    rpc ListAndWatch(Empty) returns (stream ListAndWatchResponse);

    // 分配:Pod 请求设备时,返回设备路径和环境变量
    rpc Allocate(AllocateRequest) returns (AllocateResponse);
}

Allocate 的返回内容

// NVIDIA Device Plugin 的 Allocate 返回
return &pluginapi.AllocateResponse{
    ContainerResponses: []*pluginapi.ContainerAllocateResponse{{
        Envs: map[string]string{
            "NVIDIA_VISIBLE_DEVICES": "GPU-uuid-12345",
        },
        Devices: []*pluginapi.DeviceSpec{{
            ContainerPath: "/dev/nvidia0",
            HostPath:      "/dev/nvidia0",
            Permissions:   "rw",
        }},
        Mounts: []*pluginapi.Mount{{
            ContainerPath: "/usr/local/nvidia",
            HostPath:      "/usr/local/nvidia",
            ReadOnly:      true,
        }},
    }},
}

2.2 Device Plugin 的局限

局限 具体表现 影响
整数计数 nvidia.com/gpu: 2 只是数量 不知道 GPU 型号、显存、拓扑
无属性调度 调度器看不到设备细节 可能把 T4 和 H100 混调
无共享语义 一块 GPU 只能分给一个 Pod 轻量推理也要独占整卡
静态分配 分配后不能动态调整 无法在线迁移 GPU
无拓扑感知 不传递互联信息 跨 NVLink 域通信性能暴跌

这些局限催生了两条技术路线

  1. NVIDIA 原生方案:MIG、MPS、Time-Slicing——在 Device Plugin 框架内优化
  2. 社区开源方案:HAMi、gpushare——在 Device Plugin 之上加一层中间件
  3. 下一代框架:DRA——从根本上替代 Device Plugin

三、NVIDIA 原生方案:三种 GPU 共享模式

3.1 MIG(Multi-Instance GPU)—— 硬件级分区

MIG 是 NVIDIA 在 Ampere 架构(A100)引入的硬件级 GPU 分区技术。它在物理层面将 GPU 切分为最多 7 个独立实例,每个实例拥有专用的 SM、L2 Cache 和显存控制器。

┌──────────────────────────────────────────────────────┐
│               物理 GPU (A100 80GB)                    │
├────────────┬────────────┬────────────┬───────────────┤
│  MIG 1g.10gb│  MIG 1g.10gb│  MIG 2g.20gb│  MIG 3g.40gb │
│  14 SM      │  14 SM      │  28 SM      │  42 SM      │
│  10GB HBM   │  10GB HBM   │  20GB HBM   │  40GB HBM   │
│  独立 L2    │  独立 L2    │  独立 L2    │  独立 L2    │
│  独立解码器  │  独立解码器  │  独立解码器  │  独立解码器  │
└────────────┴────────────┴────────────┴───────────────┘
  每个分区是真正独立的"迷你 GPU",故障互不影响

优点

  • 隔离性最强——硬件级别,每个分区有独立的计算和显存资源
  • 零性能开销——不存在软件层面的虚拟化损耗
  • 故障隔离——一个分区崩溃不影响其他分区

致命短板

  • 硬件限制:仅支持 A100、H100、L40 等高端卡,不支持 T4、A10、V100
  • 静态配置:切分方案必须预设,更改需要重启 GPU
  • 分区数有限:最多 7 个,且受预定义 Profile 限制
  • 碎片化:不同 Profile 组合有限,难以完全无浪费

在 K8S 中使用 MIG

# GPU Operator 配置 MIG 策略
apiVersion: v1
kind: ConfigMap
metadata:
  name: mig-config
data:
  config.yaml: |
    version: v1
    mig-configs:
      all-1g.10gb:
        - devices: all
          mig-enabled: true
          mig-devices:
            "1g.10gb": 7

---
# Pod 请求 MIG 实例
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: inference
    resources:
      limits:
        nvidia.com/mig-1g.10gb: 1    # 请求一个 1g.10gb MIG 实例

3.2 MPS(Multi-Process Service)—— 进程级共享

MPS 在 CUDA 运行时和驱动之间引入一个服务层,合并多个进程的 GPU 内核请求,实现 SM 资源的并发共享。

      不使用 MPS                        使用 MPS
┌────────────────────┐         ┌────────────────────┐
│ Process A │ Process B│         │ Process A │ Process B│
│ ┌───────┐ │ ┌──────┐│         │     │          │     │
│ │Context│ │ │Context││         │     └────┬─────┘     │
│ └───┬───┘ │ └──┬───┘│         │          ▼            │
│     │     │    │     │         │   ┌──────────────┐   │
│     ▼     │    ▼     │         │   │  MPS Server  │   │
│  时间片切换 (开销大)  │         │   │ (合并请求)    │   │
│  █A█B█A█B█A█B██     │         │   └──────┬───────┘   │
└────────────────────┘         │          ▼            │
                               │   并发执行 (开销小)    │
                               │   █AABB█AABB█AABB█   │
                               └────────────────────┘

优点:减少上下文切换,多进程可以真正并发执行

致命短板

  • 无显存隔离:所有进程共享同一显存空间,一个进程 OOM 导致全卡崩溃
  • 故障传播:一个进程的 CUDA 错误可能影响其他进程
  • 调试困难:多进程共享 GPU 时排查问题很痛苦

3.3 Time-Slicing —— 时间片轮转

最简单的共享方式——通过 GPU Operator 配置时间片策略,让多个容器分时独占 GPU:

sharing:
  timeSlicing:
    renameByDefault: false
    resources:
    - name: nvidia.com/gpu
      replicas: 4    # 每块 GPU 虚拟为 4 份

优点:配置最简单,适用于所有 NVIDIA GPU(包括 T4、A10 等)

致命短板

  • 无显存隔离:和 MPS 一样,OOM 风险不可控
  • 性能波动大:时间片切换带来不可预测的延迟
  • 无法精确控制显存:无法声明"我只要 4GB 显存"

3.4 三种方案对比总结

方案 显存隔离 算力隔离 硬件要求 配置灵活性 性能开销 适用场景
MIG ✅ 硬隔离 ✅ 硬隔离 A100/H100/L40 ❌ 静态 ~0% 高端卡多租户
MPS ❌ 无 ⚠️ 部分 所有 NVIDIA ✅ 动态 受信环境并发
Time-Slicing ❌ 无 ❌ 无 所有 NVIDIA ✅ 动态 开发测试

核心问题:在 T4、A10 等广泛使用的中端 GPU 上,NVIDIA 没有提供同时满足"显存隔离 + 动态配置"的方案。


四、HAMi:GPU 虚拟化中间件深度拆解

4.1 HAMi 是什么

HAMi(Heterogeneous AI Computing Virtualization Middleware)是 CNCF Sandbox 项目,通过纯软件方式在 Kubernetes 上实现 GPU 虚拟化切分、显存隔离和算力共享。

一句话概括 HAMi 的架构:在 Kubernetes 和 GPU 驱动之间插入一层智能中间件,在调度阶段做精细分配,在运行阶段做资源隔离。

4.2 四大核心组件

                ┌────────────────────────────────┐
                │       用户提交 GPU Pod          │
                └───────────────┬────────────────┘
                                │
                ┌───────────────▼────────────────┐
                │  ① Mutating Webhook             │
                │  • 识别 GPU 资源请求            │
                │  • 注入调度器名称               │
                │  • 注入 LD_PRELOAD 环境变量     │
                └───────────────┬────────────────┘
                                │
                ┌───────────────▼────────────────┐
                │  ② HAMi Scheduler Extender      │
                │  • Filter: 过滤显存不足的节点   │
                │  • Score: 拓扑+负载打分         │
                │  • Bind: 写入 GPU 分配到注解    │
                └───────────────┬────────────────┘
                                │
          ┌─────────────────────▼─────────────────────┐
          │  ③ HAMi Device Plugin (节点侧 DaemonSet)   │
          │  • 虚拟化物理 GPU 为多个逻辑 vGPU          │
          │  • 向 kubelet 注册虚拟资源                 │
          │  • 读取 Pod 注解,注入控制参数              │
          │  • 挂载 HAMi Core 库到容器                 │
          └─────────────────────┬─────────────────────┘
                                │
          ┌─────────────────────▼─────────────────────┐
          │  ④ HAMi Core (libvgpu.so)                  │
          │  • 通过 LD_PRELOAD 加载到容器内             │
          │  • 拦截 cudaMalloc / cudaFree              │
          │  • 拦截 cudaLaunchKernel                   │
          │  • 实施显存硬隔离 + 算力软限制              │
          └───────────────────────────────────────────┘

4.3 组件详解

① Mutating Webhook —— 入口守卫

当用户提交包含 GPU 请求的 Pod 时:

  1. 检测是否包含 nvidia.com/gpunvidia.com/gpumem 等资源
  2. 修改 schedulerNamehami-scheduler
  3. 注入 LD_PRELOAD 环境变量,指向 HAMi Core 库
  4. 注入 runtimeClassName

关键设计:对用户完全透明。用户只需声明资源需求,不需要感知 HAMi 的存在。

② Scheduler Extender —— 智能调度大脑

实现双层调度——先选节点,再选 GPU:

第一层 - 节点调度:
  Filter: 节点是否有足够显存?GPU 型号匹配?
  Score:  Binpack (集中) vs Spread (分散) + 拓扑打分

第二层 - GPU 选择:
  在选中的节点上,选择哪块 GPU?
  Binpack: 多任务共享单卡
  Spread:  分散到不同 GPU

调度结果通过 Pod Annotation 传递:

{
  "hami.io/bindGPUDevice": "GPU-uuid-xxx",
  "hami.io/gpuMemLimit": "4096",
  "hami.io/gpuCoreLimit": "50"
}

③ Device Plugin —— 节点侧资源管家

物理 GPU:  [GPU-0: A100 80GB]
               │
虚拟化后:  [vGPU-0-0] [vGPU-0-1] [vGPU-0-2] [vGPU-0-3]
               │
每个 vGPU 可分配最大 80GB 显存(实际由调度器控制)

虚拟化数量由 deviceSplitCount 参数控制(默认 10)。

④ HAMi Core (libvgpu.so) —— 运行时隔离引擎

这是 HAMi 最核心的组件。通过 LD_PRELOAD 机制加载到容器内,在用户空间拦截所有 CUDA API 调用。

显存硬隔离原理

正常调用链:
  应用 → cudaMalloc() → libcuda.so → GPU Driver → GPU

HAMi 介入后:
  应用 → cudaMalloc() → libvgpu.so (HAMi Core)
                              │
                         ┌────▼────┐
                         │ 已用量   │
                         │+ 请求量  │
                         │> 限额?   │
                         └────┬────┘
                           │      │
                          YES     NO
                           │      │
                      返回错误  放行到 libcuda.so → GPU
// 显存隔离伪代码
cudaError_t hami_cudaMalloc(void **devPtr, size_t size) {
    if (current_used + size > CUDA_DEVICE_MEMORY_LIMIT) {
        return cudaErrorMemoryAllocation;  // 拒绝:超出配额
    }
    cudaError_t result = real_cudaMalloc(devPtr, size);
    if (result == cudaSuccess) {
        current_used += size;              // 更新计数
    }
    return result;
}

算力软限制原理

// 算力限制伪代码
cudaError_t hami_cudaLaunchKernel(...) {
    if (current_sm_utilization > CUDA_DEVICE_SM_LIMIT) {
        usleep(throttle_delay);  // 延迟启动,降低算力
    }
    return real_cudaLaunchKernel(...);
}

之所以叫"软限制",是因为无法像 MIG 那样在硬件层面独占 SM,而是通过调节 kernel 启动节奏间接控制。实测约 5-15% 性能开销。

4.4 Pod 完整生命周期

1. 用户提交 Pod (nvidia.com/gpu: 1, nvidia.com/gpumem: 4000)
       │
2. Mutating Webhook 拦截
   → schedulerName = hami-scheduler
   → LD_PRELOAD = libvgpu.so
       │
3. HAMi Scheduler 调度
   → Filter: 过滤显存不足的节点
   → Score: binpack/spread 打分
   → Bind: 选定 Node-A 的 GPU-0,写入 Pod Annotation
       │
4. kubelet 调用 Device Plugin Allocate
   → 读取 Annotation,注入 CUDA_DEVICE_MEMORY_LIMIT=4000
   → 挂载 libvgpu.so 到容器
       │
5. 容器启动
   → cudaMalloc(2GB) → HAMi Core 放行 (2GB < 4GB)
   → cudaMalloc(3GB) → HAMi Core 拒绝 (2+3=5GB > 4GB)
   → 不会 OOM 影响同卡其他容器 ✅

4.5 使用示例

场景一:小模型推理(共享单卡)

apiVersion: v1
kind: Pod
metadata:
  name: bert-inference
spec:
  containers:
  - name: bert
    image: my-bert:latest
    resources:
      limits:
        nvidia.com/gpu: 1          # 1 个 vGPU
        nvidia.com/gpumem: 4000    # 4GB 显存
        nvidia.com/gpucores: 30    # 30% 算力

同一块 A100 上可以同时运行多个推理 Pod:

GPU-0 (A100 80GB):
  ├── bert-inference:   4GB 显存, 30% 算力
  ├── resnet-inference:  8GB 显存, 40% 算力
  └── vit-inference:     4GB 显存, 25% 算力
  剩余:                 64GB 显存, 5% 算力

场景二:大模型多卡部署

apiVersion: v1
kind: Pod
metadata:
  name: llama-inference
spec:
  containers:
  - name: llama
    resources:
      limits:
        nvidia.com/gpu: 4           # 4 块物理 GPU
        nvidia.com/gpumem: 80000    # 每卡 80GB (全量)
        nvidia.com/gpucores: 100    # 每卡 100% 算力

nvidia.com/gpu > 1 时,HAMi 分配的是多块物理 GPU,而非同一卡的多个 vGPU。


五、竞品全景对比

5.1 全方位对比矩阵

维度 HAMi MIG Time-Slicing 阿里 gpushare 腾讯 GPU Manager DRA (2026)
显存隔离 ✅ 硬隔离(API) ✅ 硬隔离(硬件) ❌ 无 ❌ 仅调度声明 ✅ 硬隔离(API) ✅ 取决于底层
算力隔离 ⚠️ 软限制 ✅ 硬隔离 ❌ 无 ❌ 无 ⚠️ 软限制 ✅ 支持MIG
硬件要求 所有 GPU A100/H100 所有 NVIDIA 所有 NVIDIA 所有 NVIDIA 所有 NVIDIA
异构支持 ✅ 8+厂商 ❌ 仅NVIDIA ❌ 仅NVIDIA ❌ 仅NVIDIA ❌ 仅NVIDIA ❌ 仅NVIDIA
拓扑感知
性能开销 5-18% ~0% 取决于争用 ~0% 5-15% 取决于底层
社区活跃 ⭐⭐⭐⭐ NVIDIA官方 NVIDIA官方 ⭐⭐ ⭐⭐⭐⭐⭐

5.2 选型决策树

你的集群有国产加速卡(昇腾/寒武纪/海光)吗?
  └─ YES → HAMi(唯一支持异构的方案)

你的 GPU 全部是 A100/H100 高端卡吗?
  ├─ YES → 需要最强隔离? → MIG
  │        需要灵活切分? → HAMi
  └─ NO  → 继续

多租户生产环境?
  ├─ YES → HAMi(显存隔离 + 灵活调度)
  └─ NO  → 开发测试? → Time-Slicing(最简单)

5.3 性能实测数据

AWS 官方博客在 g4dn.xlarge(1x T4 16GB)上的实测:

配置 显存 算力 (GFLOPS) 说明
基准 (无 HAMi,独占) 15GB ~4,280 基准性能
HAMi 双 Pod (Pod-1) 7GB ~1,751 基准的 41%
HAMi 双 Pod (Pod-2) 7GB ~1,747 基准的 41%

分析:两个 Pod 算力之和约 3,498 GFLOPS,比基准 4,280 存在约 18% 损耗(来自 API 劫持开销和上下文切换)。但从集群角度看,原来一块 T4 只跑一个任务,现在同时跑两个,整体吞吐提升约 64%


六、DRA 与 GPU 调度的未来

6.1 从 Device Plugin 到 DRA

2026 年 3 月,NVIDIA 正式将 GPU DRA 驱动捐赠给 CNCF,标志着 GPU 调度进入新时代。

Device Plugin 时代

resources:
  limits:
    nvidia.com/gpu: 2   # "给我 2 个 GPU"——完全的黑盒

DRA 时代

apiVersion: resource.k8s.io/v1beta1
kind: ResourceClaim
metadata:
  name: training-gpus
spec:
  devices:
    requests:
    - name: gpu
      deviceClassName: gpu.nvidia.com
      count: 8
      selectors:
      - cel:
          expression: >
            device.attributes["gpu.nvidia.com"].model == "H100" &&
            device.capacity["gpu.nvidia.com"].memory >= quantity("80Gi")
    constraints:
    - requests: ["gpu"]
      matchAttribute: "gpu.nvidia.com/numa-node"

6.2 DRA 带来的变革

Device Plugin 的世界:                   DRA 的世界:

调度器看到:                            调度器看到:
  Node-A: nvidia.com/gpu = 8           Node-A:
  (8 块 GPU,仅此而已)                    GPU-0: H100, 80GB, NVLink域A
                                          GPU-1: H100, 80GB, NVLink域A
                                          GPU-2: H100, 80GB, NVLink域A
                                          GPU-3: H100, 80GB, NVLink域A
                                          GPU-4: A100, 80GB, NVLink域B
                                          GPU-5: A100, 80GB, NVLink域B
                                          ...
                                        (型号、显存、拓扑、健康状态全可见)

核心价值:调度器终于可以基于设备属性做智能决策,而非盲目的数量匹配。

6.3 HAMi 与 DRA 的关系

短期内是互补关系:

  • DRA 解决了"调度器看不到设备属性"的问题
  • HAMi 解决了"运行时显存隔离和算力共享"的问题

长期来看,HAMi 可能需要从 Device Plugin + Scheduler Extender 迁移到 DRA 框架,以获得更原生的调度能力。


七、异构加速卡:不只是 NVIDIA

7.1 国产加速卡格局

在国内 AI 产业环境下,"异构"已经不是可选项——国产加速卡正在大规模部署:

厂商 设备 主要场景 生态成熟度
华为 Ascend 910/310 训练 + 推理 ⭐⭐⭐⭐
寒武纪 MLU 370/590 推理为主 ⭐⭐⭐
海光 DCU Z100 训练 + 推理 ⭐⭐⭐
天数智芯 BI-V150 训练 + 推理 ⭐⭐
摩尔线程 MTT S4000 推理为主 ⭐⭐
燧原 GCU T20/T21 训练 + 推理 ⭐⭐
沐曦 N100/C500 推理 + 训练 ⭐⭐

7.2 HAMi 的异构支持

HAMi 是目前唯一支持多厂商异构加速卡的 CNCF 项目。通过统一的插件架构屏蔽厂商差异:

                        HAMi 异构架构

┌─────────────────────────────────────────────────────┐
│                    HAMi Scheduler                    │
│           (统一的调度逻辑,不感知硬件差异)              │
└────────────────────────┬────────────────────────────┘
                         │
    ┌────────────┬───────┼───────┬────────────┐
    ▼            ▼       ▼       ▼            ▼
┌────────┐ ┌────────┐ ┌──────┐ ┌──────┐ ┌────────┐
│ NVIDIA │ │ Ascend │ │ MLU  │ │ DCU  │ │ 天数智芯│
│ Device │ │ Device │ │Device│ │Device│ │ Device │
│ Plugin │ │ Plugin │ │Plugin│ │Plugin│ │ Plugin │
└───┬────┘ └───┬────┘ └──┬───┘ └──┬───┘ └───┬────┘
    ▼          ▼         ▼        ▼          ▼
┌────────┐ ┌────────┐ ┌──────┐ ┌──────┐ ┌────────┐
│ A100   │ │Ascend  │ │MLU   │ │ DCU  │ │BI-V150 │
│ H100   │ │  910   │ │ 590  │ │ Z100 │ │        │
└────────┘ └────────┘ └──────┘ └──────┘ └────────┘

统一的用户体验——不管底层是什么硬件,Pod YAML 只需声明对应的资源类型:

# NVIDIA GPU
resources:
  limits:
    nvidia.com/gpu: 1
    nvidia.com/gpumem: 4000

# 华为 Ascend
resources:
  limits:
    huawei.com/Ascend910: 1

# 寒武纪 MLU
resources:
  limits:
    cambricon.com/vmlu: 1

7.3 混合集群管理

在实际生产中,一个集群可能同时存在多种加速卡。HAMi + 节点标签 + 亲和性调度可以实现混合管理:

# 节点标签标识加速卡类型
# GPU 节点
kubectl label node gpu-node-1 accelerator=nvidia-h100

# NPU 节点
kubectl label node npu-node-1 accelerator=ascend-910

# Pod 通过亲和性选择硬件
apiVersion: v1
kind: Pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: accelerator
            operator: In
            values: ["nvidia-h100"]
  containers:
  - name: training
    resources:
      limits:
        nvidia.com/gpu: 8

八、GPU Operator:自动化管理 GPU 全栈

8.1 为什么需要 GPU Operator

手动管理 GPU 环境是一场噩梦:安装驱动、配置容器运行时、部署 Device Plugin、设置监控……每个 GPU 节点都要重复这些步骤,而且驱动升级时还要逐节点操作。

GPU Operator 的理念是:用 Operator 模式自动管理 GPU 全栈组件的生命周期。

┌───────────────────────── GPU Operator 管理的组件 ─────────────────────────┐
│                                                                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐ │
│  │ NVIDIA Driver│  │  Container   │  │   Device     │  │    DCGM      │ │
│  │  (驱动)      │  │  Toolkit     │  │   Plugin     │  │  Exporter    │ │
│  │              │  │  (容器运行时) │  │  (设备管理)   │  │  (GPU 监控)   │ │
│  └──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘ │
│                                                                           │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐                   │
│  │ GPU Feature  │  │    MIG       │  │  Validator   │                   │
│  │ Discovery    │  │  Manager     │  │  (验证)      │                   │
│  │ (特征发现)   │  │  (MIG 管理)  │  │              │                   │
│  └──────────────┘  └──────────────┘  └──────────────┘                   │
│                                                                           │
│  所有组件以 DaemonSet 形式运行,由 GPU Operator 统一管理生命周期           │
└───────────────────────────────────────────────────────────────────────────┘

8.2 安装与配置

# 安装 GPU Operator
helm install --wait gpu-operator nvidia/gpu-operator \
  -n gpu-operator --create-namespace \
  --set driver.enabled=true \
  --set driver.version="550.54.15" \
  --set toolkit.enabled=true \
  --set devicePlugin.enabled=true \
  --set dcgmExporter.enabled=true \
  --set migManager.enabled=true \
  --set gfd.enabled=true

8.3 GPU Feature Discovery

GPU Feature Discovery 自动为每个 GPU 节点打上详细的标签:

kubectl get node gpu-node-1 --show-labels | grep nvidia
# nvidia.com/gpu.family=hopper
# nvidia.com/gpu.memory=81920
# nvidia.com/gpu.count=8
# nvidia.com/gpu.product=NVIDIA-H100-SXM5-80GB
# nvidia.com/mig.capable=true
# nvidia.com/gpu-driver.version=550.54.15
# nvidia.com/cuda.driver.major=12
# nvidia.com/cuda.driver.minor=4

这些标签可用于 Pod 的节点亲和性调度,确保训练任务调度到正确的 GPU 型号上。


九、拓扑感知调度实战

9.1 Topology Manager

Kubernetes 内建的 Topology Manager 确保 GPU、CPU 和内存的 NUMA 亲和性:

# kubelet 配置
apiVersion: kubelet.config.k8s.io/v1beta1
kind: KubeletConfiguration
topologyManagerPolicy: "best-effort"    # none | best-effort | restricted | single-numa-node
topologyManagerScope: "pod"             # container | pod
策略 行为 适用场景
none 不做拓扑对齐 默认值
best-effort 尽力对齐,不强制 通用场景
restricted 必须对齐,否则 Pod 被拒绝 性能敏感
single-numa-node 所有资源必须来自同一 NUMA AI 训练推荐

9.2 HAMi 的 linkZone 概念

HAMi 引入了 linkZone 来感知 GPU 互联拓扑:

当任务请求 4 块 GPU 时:

✅ HAMi 拓扑感知: 分配 GPU-0~3 (同一 NVSwitch 域, NVLink 900GB/s)
❌ 无拓扑感知:    分配 GPU-0,2,5,7 (跨域, PCIe 128GB/s)

性能差距: ~7倍

9.3 在 Pod 中利用拓扑

apiVersion: v1
kind: Pod
spec:
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: training-job
            operator: In
            values: ["llm-pretrain"]
        topologyKey: "topology.kubernetes.io/zone"
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: nvidia.com/gpu.product
          operator: In
          values: ["NVIDIA-H100-SXM5-80GB"]
  containers:
  - name: worker
    resources:
      limits:
        nvidia.com/gpu: 8

十、总结与下一篇预告

本篇核心要点回顾

1. GPU 硬件基础:
   └── SM/CUDA Core/Tensor Core/HBM/NVLink
   └── 互联拓扑直接影响性能 (NVLink 900GB/s vs PCIe 128GB/s)

2. Device Plugin:
   └── K8S 管理 GPU 的基础框架
   └── 局限: 整数计数,无属性,无共享

3. NVIDIA 原生方案:
   └── MIG: 硬件级分区 (最强隔离,仅高端卡)
   └── MPS: 进程共享 (无显存隔离)
   └── Time-Slicing: 时间片 (最简单,无隔离)

4. HAMi GPU 虚拟化:
   └── 四组件: Webhook → Scheduler → Device Plugin → Core
   └── 核心: LD_PRELOAD + CUDA API 劫持实现显存隔离
   └── 唯一支持异构加速卡的 CNCF 方案

5. DRA (下一代):
   └── 基于属性的声明式资源请求
   └── NVIDIA 已捐赠 GPU DRA 驱动给 CNCF

6. 异构管理:
   └── 华为 Ascend / 寒武纪 MLU / 海光 DCU 等
   └── HAMi 统一管理多厂商加速卡

7. 选型:
   └── 国产卡 → HAMi
   └── 高端卡 + 强隔离 → MIG
   └── 中端卡 + 多租户 → HAMi
   └── 开发测试 → Time-Slicing

下一篇预告

现在你理解了 GPU 在 K8S 上的管理机制。但管理单块 GPU 只是起点——真正的挑战是:如何在几百台 GPU 服务器上构建一个完整的 AI 算力平台?

第 4 篇《AI 算力平台架构设计:从调度到编排的全栈实战》 将进入平台级设计:

  • AI 工作负载和传统应用到底有哪些本质区别?
  • 一个生产级 AI 算力平台应该分几层?每层放什么组件?
  • Gang 调度怎么实现"128 个 Pod 同时启动或全部不启动"?
  • Kubeflow、Volcano、KServe、Kueue 各自解决什么问题?
  • 单集群撑不住了怎么办?多集群联邦架构怎么设计?
  • Google GKE、AWS EKS、阿里云 ACK 的 AI 方案哪个更适合你?

从"管理 GPU"到"构建平台",复杂度上了一个数量级。


参考资料

  1. NVIDIA H100 Tensor Core GPU Architecture - H100 架构白皮书
  2. NVIDIA Multi-Instance GPU (MIG) - MIG 官方文档
  3. NVIDIA GPU Operator - GPU Operator 文档
  4. HAMi GitHub Repository - HAMi 开源代码
  5. HAMi Official Documentation - HAMi 官方文档
  6. AWS Blog - GPU Virtualization with HAMi - AWS HAMi 实测
  7. Device Plugins - kubernetes.io - Device Plugin 文档
  8. Dynamic Resource Allocation - kubernetes.io - DRA 文档
  9. NVIDIA GPU Sharing in K8S - GPU 共享方案
  10. Topology Manager - kubernetes.io - 拓扑管理器文档

关注公众号「coft」,获取更多 AI 实战干货和 AI-Infra 深度教程。

posted @ 2026-03-28 23:39  warm3snow  阅读(24)  评论(0)    收藏  举报