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 域通信性能暴跌 |
这些局限催生了两条技术路线:
- NVIDIA 原生方案:MIG、MPS、Time-Slicing——在 Device Plugin 框架内优化
- 社区开源方案:HAMi、gpushare——在 Device Plugin 之上加一层中间件
- 下一代框架: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 时:
- 检测是否包含
nvidia.com/gpu、nvidia.com/gpumem等资源 - 修改
schedulerName为hami-scheduler - 注入
LD_PRELOAD环境变量,指向 HAMi Core 库 - 注入
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"到"构建平台",复杂度上了一个数量级。
参考资料
- NVIDIA H100 Tensor Core GPU Architecture - H100 架构白皮书
- NVIDIA Multi-Instance GPU (MIG) - MIG 官方文档
- NVIDIA GPU Operator - GPU Operator 文档
- HAMi GitHub Repository - HAMi 开源代码
- HAMi Official Documentation - HAMi 官方文档
- AWS Blog - GPU Virtualization with HAMi - AWS HAMi 实测
- Device Plugins - kubernetes.io - Device Plugin 文档
- Dynamic Resource Allocation - kubernetes.io - DRA 文档
- NVIDIA GPU Sharing in K8S - GPU 共享方案
- Topology Manager - kubernetes.io - 拓扑管理器文档
关注公众号「coft」,获取更多 AI 实战干货和 AI-Infra 深度教程。

浙公网安备 33010602011771号