跳转到文档内容
版本:v2.10.0

NVIDIA 动态 MIG 实现

介绍

HAMi v2.10 用预留优先的动态 MIG 架构取代了预定义的 knownMigGeometries 和整卡模板切换。硬件能力来源于节点,调度器在绑定 Pod 之前预留确切的 MIG placement,NVIDIA device plugin 负责创建和回收对应的 GPU 实例(GI)和计算实例(CI)。

该设计将四项职责分离:

权威来源职责
节点上的 NVML上报 profile 的显存、算力、切片数量和合法 placement
HAMi 调度器选择物理 GPU、profile 和 placement,并对预留进行核算
NVIDIA device plugin串行化硬件变更,创建、校验、接管和销毁 GI/CI 实例
Pod 注解持久化调度器与 device plugin 共享的分配身份

这一模型为每个 Pod 创建硬件隔离的 MIG 设备,同时既不让调度器直接修改 GPU 硬件,也不让 device plugin 在运行时另选 placement。

设计目标

  • 以节点和 NVML 作为硬件能力的事实来源。
  • 预留拓扑,而不仅仅是 MIG 切片总数。
  • 严格按调度器接受的 profile 和 placement 创建实例。
  • 使用稳定的工作负载元数据进行协调和重启恢复。
  • 回收单个 Pod 的实例时不重新配置其他 Pod 拥有的实例。
  • 随着 GPU 密度增长,保持调度器/device plugin 共享契约的紧凑。

架构

Kubernetes control plane

+----------------+ Node capability +----------------+
| Device Plugin | --------------------------> | HAMi Scheduler |
| | | |
| NVML discovery | Pod reservation | Placement |
| GI/CI manager | <-------------------------- | policy |
| Reconciler | | Capacity model |
+-------+--------+ +--------+-------+
| |
| exact GI/CI realization | bind
v v
+----------------+ +----------------+
| NVIDIA GPU | | Workload Pod |
| MIG topology | | Allocation |
| and instances | | annotation |
+----------------+ +----------------+

device plugin 在 NVIDIA 节点注册注解中发布能力。调度器根据活动 Pod 的预留重建拓扑占用情况。Pod 注解是调度阶段与运行阶段之间的持久交接点。

能力发现契约

策略来自 migProfileAllowlist

调度器设备配置为每种型号指定集群策略允许的 profile:

nvidia:
migProfileAllowlist:
- models: ["A100-SXM4-40GB"]
profiles: ["1g.5gb", "2g.10gb", "3g.20gb", "7g.40gb"]
- models: ["RTX PRO 6000 Blackwell Server Edition"]
profiles: ["1g.24gb", "2g.48gb", "4g.96gb"]

Chart 的默认配置还包含 A30、A100 80 GB、H100、H20、H200 和 B200 的映射。允许列表决定集群允许什么,并不定义容量或完整的几何配置。

自定义的 device-config.content 值或外部 ConfigMap 会替换 Chart 默认配置。此类配置必须显式使用 migProfileAllowlist。旧的 knownMigGeometries 字段不会被自动转换。

能力来自 NVML

对于匹配 GPU 上每个允许的 profile,device plugin 会向 NVML 查询 profile 信息和可能的 placement,并在 hami.io/node-nvidia-register 中每块 GPU 的 migProfiles 数组里发布面向调度器的字段:

{
"name": "2g.10gb",
"memoryMB": 9984,
"core": 29,
"sliceCount": 2,
"placements": [
{ "start": 0, "size": 2 },
{ "start": 2, "size": 2 },
{ "start": 4, "size": 2 }
]
}
字段调度器用途
name跨组件稳定的 profile 标识
memoryMBnvidia.com/gpumem 需求与实际上报的容量进行匹配
core核算该 profile 的算力份额
sliceCount对候选 profile 进行确定性排序
placements选择合法且不重叠的物理切片区间

profile 名称是策略标签,而其显存、算力和 placement 数据是节点本地的事实。未列入允许列表或 NVML 无法解析的 profile 会被省略。当 placement 已经能表达可调度容量时,仅 device plugin 使用的发现数据(例如最大实例数)不会加入共享的传输格式。

调度与预留

对于选择了 nvidia.com/vgpu-mode: "mig" 的 Pod,调度按以下顺序进行:

  1. 根据活动 Pod 的预留重建每块 GPU 已占用的区间。
  2. 按 NVML 上报的显存和切片数量对已发现的候选 profile 排序。
  3. 选择能满足容器显存请求的最小 profile。
  4. 选择一个确定性的合法 placement,且不与现有或新接受的预留重叠。
  5. 在 Pod 绑定之前,立即将该预留计入调度器占用。
  6. 将完整的逻辑预留持久化到 Pod 中。

一个 placement 占用半开区间 [placement.start, placement.start + placement.size)。如果请求的 profile 上报的所有 placement 都无法在不重叠的前提下放入,那么即使空闲切片总数足够也不行,此时 Pod 会保持 Pending。调度器不会请求切换整卡模板,也不会移动正在运行的 GI。

Pod 预留契约

调度器向 hami.io/vgpu-mig-allocations 写入一个 JSON 数组,每个申请的 MIG 设备对应一个条目:

[
{
"containerIndex": 0,
"deviceIndex": 0,
"gpuUUID": "GPU-xxxxxxxx",
"profile": "2g.10gb",
"placement": { "start": 2, "size": 2 },
"migUUID": "MIG-xxxxxxxx",
"gpuInstanceID": 4,
"computeInstanceID": 0
}
]

调度器写入 containerIndexdeviceIndexgpuUUIDprofileplacement。运行时身份字段最初不存在。实例创建完成后,device plugin 会在同一条记录中补充 migUUIDgpuInstanceIDcomputeInstanceID

容器索引和设备索引用于区分同一块物理 GPU 上的多次分配。只有三个运行时字段全部存在时,运行时身份才有效;不完整的运行时身份无法通过校验。该注解是内部协议,用户不得生成或修改。

运行时创建

在 kubelet Allocate 阶段,device plugin 解析正在启动的容器对应的条目,并执行以下操作:

  1. 将已跟踪的实例与当前活动 Pod 快照进行协调。
  2. 校验预留的 profile 和 placement 仍然存在于 NVML 能力中。
  3. 获取按物理 GPU 划分的变更锁。
  4. 严格在调度器选定的 placement 上创建 GI,并创建其 CI。
  5. 解析 MIG UUID、GI ID 和 CI ID,并将 MIG 设备暴露给容器。
  6. 用该运行时身份更新 Pod 的分配注解。

管理器的键由物理 GPU 索引、profile、placement 起点和 placement 大小组成。针对同一预留的重复 Allocate 调用会返回同一个受管 MIG UUID。如果多设备分配中途失败,本次尝试创建的实例会被回滚;已接管的实例不会作为回滚的一部分被销毁。

device plugin 绝不会改用其他物理 placement 重试。那样会破坏调度器的拓扑核算,并可能与另一个已接受的预留重叠。

协调与回收

device plugin 会定期列出分配到其节点的 Pod。拥有有效预留、未处于删除中且未达到 Succeeded 或 Failed 状态的 Pod 构成期望分配集合。不在该集合中的受管实例会通过精确销毁其 CI 和 GI 来释放。

协调有意保持保守。只有完整的 Kubernetes 列表和有效的分配注解才能授权一次清理。API 失败、格式错误的记录或不完整的运行时身份都会导致跳过破坏性协调,而不是让插件自行推断所有权。

这个收敛循环让 placement 在其 Pod 终止后可以被重新使用,同时保持同一块 GPU 上无关的 placement 不受影响。

device plugin 重启接管

启动恢复同时使用 Kubernetes 分配状态和 NVML 活动信息:

  1. 通过活动 Pod 预留和 GPU 进程状态识别正在承载工作负载的 GPU。
  2. 将空闲 GPU 准备为干净的 MIG 就绪状态;这些空闲 GPU 上的旧 GI/CI 实例可能会被移除。
  3. 对每条活动的 v2.10 记录,插件根据 NVML 校验注解中的 profile、placement、MIG UUID、GI ID 和 CI ID。
  4. 匹配的活动实例会被接管到新管理器的分配映射中。
  5. 从重建的所有权状态继续进行常规协调。

如果启动时无法可靠读取分配状态,插件会保留 GPU,而不是执行破坏性的空闲 GPU 清理。旧的 GPU-UUID[template-slot] 标识无法被接管,因为它们不能证明物理 placement 和完整的运行时身份。

NVML 会话归属

v2.10.0 的 device plugin 在构造插件时初始化 MigInstanceManager,并在插件的 context 结束时关闭管理器。这种按插件生命周期持有会话的方式由 HAMi PR #2610 引入。

每个启动周期单独初始化、等待已接受操作执行完毕以及安全地重复关闭,是之后的 HAMi PR #2989 添加的。上述这些后续版本的生命周期保证不适用于 v2.10.0。

指标与可观测性

调度器通过当前指标导出已创建的实例:

# HELP hami_node_gpu_mig_instance_info Realized MIG instance identity and scheduler placement
# TYPE hami_node_gpu_mig_instance_info gauge
hami_node_gpu_mig_instance_info{compute_instance_id="0",device_index="0",device_uuid="GPU-xxxxxxxx",gpu_instance_id="4",mig_uuid="MIG-xxxxxxxx",node="MIG-NODE-A",placement_size="2",placement_start="2",profile="2g.10gb",zone="vGPU"} 1

只有补充了完整运行时身份的预留才会产生该序列。其标签将调度器预留与物理 GPU、placement、MIG UUID、GI ID 和 CI ID 关联起来。device_uuid 加上 gpu_instance_id 还可以与携带 UUIDGPU_I_ID 的 DCGM 序列关联。

nodeGPUMigInstance 是兼容性指标,仅在 legacyMetrics: true 时输出;当前 Chart 默认值为 false。使用默认 NodePort 服务时,标准的调度器端点为 <scheduler-ip>:31993/metrics

有用的运维信号包括:

  • device plugin 的发现日志以及每块 GPU 非空的 migProfiles
  • 调度器的 placement 决策,以及在容量或碎片压力下保持 Pending 的 Pod;
  • hami.io/vgpu-mig-allocations 从逻辑预留到运行时身份的转变;
  • 通过 nvidia-smi 或 NVML 观察到的 GI/CI;
  • 回收与启动接管日志;
  • device plugin 重启前后工作负载的持续进展。

迁移与所有权边界

旧版 HAMi 几何配置实现

v2.9 和 v2.10 协议无法作为混合的调度器/device plugin 组合安全地服务 MIG 工作负载。旧调度器发布并消费 migtemplate 和模板/slot 标识;v2.10 消费 migProfiles,并要求确切的 profile/placement 预留。

因此首次迁移需要受控的交接:

  1. 停止新的 MIG 调度,并逐节点 drain 旧 MIG Pod;
  2. knownMigGeometries 中所需旧 profile 的并集转换为 migProfileAllowlist
  3. 先升级调度器,再升级节点上的 device plugin;
  4. 验证能力发布、实例创建、回收和重启接管;
  5. 只有在生命周期测试通过后,才解除各节点的 cordon。

迁移后,只要存在合法的空闲 placement,日常的混合 profile 创建不需要切换整卡几何配置。硬件碎片化、MIG 模式变更、驱动维护、回滚,或需要移动活动 GI 的布局,仍可能需要 drain 或重启。

NVIDIA MIG Manager

MIG Manager 应用节点级或 GPU 级的几何配置,而 HAMi 动态 MIG 根据每个 Pod 的预留创建和销毁 GI/CI 实例。两者修改的是同一份硬件状态,不能同时协调同一块物理 GPU。

GPU Operator 可以继续提供 NVIDIA 驱动、Container Toolkit、DCGM 及其他基础设施。在 HAMi 接管变更所有权之前,先停止 MIG Manager 的协调,并确保没有控制器会重新创建它或重新应用 nvidia.com/mig.config。只删除一个 MIG Manager Pod 而不改变其控制器策略,并不能建立这一边界。

当前 Chart 允许列表、迁移检查清单、工作负载示例和验证命令,请参阅动态 MIG 用户指南。如果要从旧版几何配置实现或 NVIDIA MIG Manager 升级,分阶段回滚方案和验证检查清单等面向运维的迁移步骤请参阅迁移到 HAMi 动态 MIG

演进方向

能力契约、预留契约和硬件所有权边界是设计上希望长期保持稳定的部分。在此基础上,后续可以扩展可插拔的 placement 策略、节点级碎片打分、感知 placement 的调度器指标、事件驱动的生命周期加速、动态 MIG 身份的 CDI 同步,以及更广泛的多 GPU 和异构节点验证。

特别感谢

感谢 @sailorvii 帮助实现了最初的动态 MIG 功能。

CNCFHAMi 是 CNCF 孵化项目