ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

HAMi 动态 MIG 架构解析:从能力契约到生命周期回收的 Reservation-First 设计

2026/9/18 10:50:18 拓冰建站 浏览量
HAMi 动态 MIG 架构解析:从能力契约到生命周期回收的 Reservation-First 设计 HAMi 动态 MIG 架构解析从能力契约到生命周期回收的 Reservation-First 设计【免费下载链接】HAMiHeterogeneous GPU Sharing on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ha/HAMi导读本文基于 docs/develop/mig-dynamic-deallocate.md 展开深入剖析 HAMiHeterogeneous GPU Sharing on Kubernetes动态 MIG 的完整架构节点如何通过 NVML 发布 MIG 能力契约调度器如何以先预留、后实现reservation-first的方式为每个 Pod 精确选定 GPU、MIG Profile 与物理放置placement设备插件如何在分配阶段按预留创建 GI/CI 实例、并在 Pod 终止后精确回收。读完本文你将掌握hami.io/vgpu-mig-allocations预留契约的字段语义、能力契约与预留契约的协作方式、调度到回收的完整生命周期以及设备插件重启后的实例收养与一致性模型。背景为什么需要动态 MIGNVIDIA MIGMulti-Instance GPU把一块物理 GPU 划分成多个硬件级隔离的计算实例。GPU 型号通过 NVML 暴露 Profile 容量与放置规则而 Kubernetes 通过声明式资源进行调度。传统做法包括 HAMimaster分支早期的knownMigGeometries模板实现以及 NVIDIA GPU Operator MIG Manager 的固定几何体都需要在整块 GPU 上预置固定几何布局当工作负载形态变化、新请求无法匹配当前布局时必须清空 GPU、销毁既有 GI/CI、切换整套布局生产上通常需要 cordon/drain 节点代价高昂。HAMi 动态 MIG 用预留优先架构连接这两层节点发布硬件能力 → 调度器预留精确的 Profile 与放置 → 设备插件在容器分配阶段按预留实现 → Pod 元数据在生命周期中携带分配身份。这样日常的混合 Profile 调度、Pod 删除后的实例回收、空闲放置复用都不再需要整卡切换布局。相关迁移路径详见 Migrating to HAMi Dynamic MIG本文聚焦当前架构本身的设计。设计目标与原则五个设计目标动态 MIG 架构追求五个可验证的结果硬件能力来源于拥有 GPU 的节点本身——Profile 容量、内存、算力、放置规则都由节点上的 NVML 提供调度器不维护硬件台账调度决策包含物理 MIG 放置——调度器不仅要选卡还要精确到[start, startsize)的切片区间运行时实现严格跟随调度预留——设备插件创建的实例必须与调度器预留的 Profile Placement 完全一致不自行就近变通工作负载元数据支持对账与重启恢复——Pod 注解承载分配身份重启后据此重建内存索引、收养活跃实例跨组件契约保持紧凑稳定——节点注解不随 GPU 密度线性膨胀共享 API 只暴露调度所需字段。四项核心原则原则含义硬件权威Hardware authorityNVML 定义 Profile 容量与合法放置设备插件把这一信息翻译成面向调度器的能力契约显式预留Explicit reservation调度器在绑定前选定物理 GPU、MIG Profile 与放置每个被接受的分配立即计入调度器占用清晰归属Clear ownership调度器拥有放置策略设备插件拥有硬件变更Pod 注解是两者之间持久的交接物收敛生命周期Convergent lifecycle稳定的预留键GPUProfilePlacement支持幂等实现对账Reconciliation让受管硬件向活跃工作负载预留收敛总体架构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节点硬件权威。发现白名单 Profile、发布紧凑能力契约、准备 MIG-ready GPU、实现预留、记录运行时 MIG UUID、重启后收养活跃实例、对账受管实例与活跃 Pod。HAMi 调度器Scheduler策略与预留权威。读取节点能力、重建拓扑占用、把工作负载需求匹配到 Profile、选择合法放置、在绑定前持久化预留。Pod 分配记录Pod Allocation Record连接调度、运行时实现、对账与重启恢复的持久化系统记录。在源码中这一职责切分可以清晰看到调度器侧的设备抽象 定义了MigPlacement、MigProfile、MigAllocation、AllowedMigProfiles等共享类型其中MigTemplate/MigTemplateUsage等旧模板类型已标注 Deprecated仅供非 NVIDIA 后端与测试兼容动态 MIG 不再使用设备插件侧的MigInstanceManager则是节点上活的 GICI 状态的唯一权威。NVML 会话所有权模型动态 MIG 对 NVML 会话的持有有严格约定每个插件启动周期通过MigInstanceManager拥有一个NVML 会话。在 migmgr.go 中Init获取会话并在启动扫描前完成初始化MIG 发现、注册、拓扑评分、分配、收养与释放都复用该实例。Start初始化 NVML → 启动扫描发现 Profile 与放置→ 注册 → 拓扑评分 → 分配/收养/释放Stop取消该周期的注册与对账循环 → 停止 gRPC 并等待 handler含分配清理→ 排空后台 worker → 关闭 manager。Shutdown拒绝新操作并等待已准入的操作完成migmgr.go通过operations.WaitGroup保证操作在 NVML 释放前结束启动失败复用同一清理路径失败的初始化绝不会与关闭配对重复关闭安全closingchannel 幂等新启动获取新会话并根据 Pod 注解重建内存中的分配索引关闭本身不会销毁正在运行的实例初始资源发现、健康检查、非 MIG 操作与独立 monitor 各自保留独立的会话所有权——一初始化一关闭不变量仅针对动态 MIG manager 的会话而非进程中每个 NVML 调用者强制进程终止无法执行优雅清理因此生产上应以 Kubernetes 管理插件生命周期。能力契约Capability Contract设备插件把允许的 MIG Profile 发布到 NVIDIA 节点注册注解中字段面向调度需求{ name: 2g.10gb, memoryMB: 9984, core: 29, sliceCount: 2, placements: [ {start: 0, size: 2}, {start: 2, size: 2}, {start: 4, size: 2} ] }字段用途name调度器与设备插件共用的 Profile 身份memoryMB工作负载容量匹配core调度器资源记账sliceCount确定性的 Profile 排序placementsNVML 报告的合法拓扑选择对应源码结构体 MigProfile 完全一致MemoryMB、Core、SliceCount、Placements其中InstanceCount字段标记json:-仅设备插件用于推导物理 GPU 的广告副本数不进入调度器线格式——因为placements已描述了可调度的 MIG 容量。设备本地的发现数据保留在设备插件进程内不写入节点注解。这个紧凑边界控制了注解增长也让共享 API 与调度需求对齐。Profile 白名单表达集群策略NVML 提供容量与拓扑两者共同定义调度器可见的能力。配置层面NvidiaConfig 中的MigProfileAllowlist[]device.AllowedMigProfiles结构见 devices.go只声明models与profiles两个字段core/memory/count/放置全部由节点 NVML 实测得出ValidateMigProfileAllowlist 只做策略校验模型与 Profile 非空、Profile 形如Ng.xxx不校验容量。预留契约Reservation Contract调度器把预留写入hami.io/vgpu-mig-allocations注解{ containerIndex: 0, deviceIndex: 0, gpuUUID: GPU-xxxxxxxx, profile: 2g.10gb, placement: {start: 2, size: 2}, migUUID: MIG-xxxxxxxx, gpuInstanceID: 4, computeInstanceID: 0 }调度器写入容器身份、父 GPU、Profile 与放置设备插件在实现后补充 MIG UUID、GPU Instance ID 与 Compute Instance ID。这些字段共同构成跨控制面与节点生命周期操作的一个分配身份。父 GPU UUID GPU Instance ID 为携带UUID与GPU_I_IDlabel 的 DCGM 指标提供了直接关联键。源码实现位于 mig_allocations.go常量MigAllocationsAnnotation hami.io/vgpu-mig-allocationsL26另有migProfile/migPlacement两个 CustomInfo 键L28-L31MigAllocation 结构体与 JSON 契约一一对应MigUUID/GPUInstanceID/ComputeInstanceID为omitempty运行时字段EncodeMigAllocationsL48-L77把PodSingleDevice中带完整 CustomInfo 的切片编码为注解要求 Profile 非空且Placement.Size 0DecodeMigAllocationsL79-L112是严格的校验器拒绝不完整项负数索引、空 UUID/Profile/Size、拒绝部分运行时身份三个运行时字段必须要么全空、要么齐全见 L92-L104、拒绝同一(containerIndex, deviceIndex)重复。这套校验在插件重启重建索引与对账时兜底避免猜测性删除。调度器在PatchAnnotationsdevice.go中写入该注解。该注解由调度器与设备插件管理是重建调度占用、插件重启恢复、实例回收的持久契约用户不应手动创建或修改它迁移文档 dynamic-mig-migration.md 亦有明确说明。核心工作流1. 能力发布Capability publication设备插件通过 NVML 发现白名单 Profile 集合并把紧凑能力契约写入节点注册注解hami.io/node-nvidia-register见 device.go。调度器状态刷新把该契约转换为每 GPU 的拓扑容量。验证清单要求注册的 GPUmode为mig、migProfiles对每块目标 GPU 非空、Profile 内存/切片数/放置与 NVML 能力一致。2. 调度与预留Scheduling and reservation调度器从活跃 Pod 预留重建占用。每个放置占用区间[start, startsize)。Profile 选择遵循最小覆盖优先migProfileForMemorydevice.go在migProfileCandidates结果里返回内存恰好覆盖请求的最小 ProfilemigProfilesByMemoryL712-L722以内存升序、同内存按SliceCount升序稳定排序保证确定性。放置选择遵循确定性打包。容量压力下工作负载停留在 Kubernetes Pending 阶段。调度 Fit 流程device.go的关键细节MIG 模式下切片按Profile 容量记账而非原始请求L1017-L1028先通过plannedMigProfile解析出 Profile再把profile.MemoryMB/profile.Core用于配额与内存/算力检查planMigContainerL783-L798先尝试联合规划planMigAllocations失败则回退到顺序规划planMigSequentially允许把请求升级到更大的 ProfilerecordMigPlansL802-L844把联合规划的 Profile 与放置记录到每个候选切片的CustomInfo[migProfile]/CustomInfo[migPlacement]供AddResourceUsage提交布局时复用AddResourceUsageL870-L893先验证既有计划plannedMigAllocation仍合法且无冲突L846-L864否则重新selectMigCandidate并把分配追加到MigAllocationsInUse立即计入占用。偏置 Profile 选择mig-profile-preference因为 MIG 把内存与算力耦合两个 Profile 可能用不同算力覆盖同一内存请求在 A100-40GB 上 20GB 请求总是解析为3g.20gb即使允许4g.20gb。需要额外算力的 Pod 可设置nvidia.com/mig-profile-preference注解为有序、逗号分隔的列表apiVersion: v1 kind: Pod metadata: name: mig-prefer-4g annotations: nvidia.com/vgpu-mode: mig nvidia.com/mig-profile-preference: 4g spec: containers: - name: workload image: ubuntu:22.04 command: [bash, -c, sleep 3600] resources: limits: nvidia.com/gpu: 1 nvidia.com/gpumem: 20000实现见 mig_preference.go条目可精确命名4g.20gb或以切片类别命名4g跨 GPU 型号通用migProfileCandidatesL71-L92把首选条目按列出的顺序置前其余 Profile 按默认顺序补齐。偏好是偏置而非硬性要求不会选小于内存请求的 Profile、只作用于白名单内、首选无空闲放置或布局放不下时回退默认顺序绝不因此拒绝整卡。webhook 侧的validateMigProfilePreferenceL107-L125在创建时拒绝不匹配任何白名单条目的拼写错误测试见 mig_preference_test.go。3. 运行时实现Runtime realizationkubelet 分配阶段设备插件解析预留并与当前 NVML 能力核对。MigInstanceManager的EnsureAllocationmigmgr.go是核心实现路径预留键 (GPUIndex, Profile, Placement)先查byAllocation缓存命中则幂等返回既有 MIG UUIDL421-L427确认 MIG 模式已启用ensureMigModeEnabled通过profileSliceKey把2g.10gb归一为2g映射到 NVML 的 GI Profile ID 与 CI Profile IDL432-L440向 NVML 查询该 Profile 的合法放置集合校验调度器选定的放置必须合法L449-L462否则报错而非变通按CreateGpuInstanceWithPlacement创建 GI再创建 CIL463-L481任意一步失败都销毁已建部分gi.Destroy()/ci.Destroy()回滚自己的部分分配通过findMigUUIDForGIL628-L651枚举 MIG 设备、按 GI ID 反查运行时 MIG UUID登记byAllocation与byAllocationMigUUID双索引L494-L498。每物理 GPU 一个互斥锁gpuLockL159-L168串行化同一 GPU 上的变更避免并发创建冲突。重复分配请求相同 GPUProfilePlacement收敛到同一受管实例天然幂等。AllocationRuntimeInfoL503-L518把 MIG UUID/GI ID/CI ID 回填到 Pod 分配记录最终在 allocate.go 层面写入注解。4. 生命周期对账Lifecycle reconciliationReconcileActiveAllocationsmigmgr.go从节点上活跃 Pod 推导期望分配集合与受管实例比较释放已结束工作负载的分配对不在active集合中的每个预留键销毁 GI/CI 并从双索引删除。对账周期性运行、也在新分配活动时触发支撑稳态清理与及时容量复用。保守性设计每个清理周期由完整的 Kubernetes 状态快照授权——API/注解读取失败时跳过破坏性对账绝不猜测性删除实例迁移文档的验证清单第 8 条正是Kubernetes API 临时不可用时不得破坏性回收。5. 重启恢复Restart recovery启动时把活跃 Pod 预留与 NVML 进程活动结合识别承载活跃工作的 GPU空闲 GPUResetIdleGPUsmigmgr.go进入干净的 MIG-ready 状态——启用 MIG 模式并销毁其上既有 GI/CI忙碌 GPU 绝不动活跃记录含 Profile、Placement、MIG UUID 的完整注解通过AdoptAllocationL520-L580与 NVML 实测核对Profile ID、放置、GI 枚举、MIG UUID、CI ID 逐项匹配核对成功则收养进新 manager 的byAllocation/byAllocationMigUUID索引核对失败返回annotated allocation is not live错误。这一流程保留了工作负载身份并在设备插件重启后重新建立生命周期归属。注意任何来自用户/外部的注解都不可信收养前必须与 NVML 状态交叉验证防止把两个预留映射到重叠切片。一致性模型动态 MIG 遵循预留优先的五步序列节点能力成为调度器输入调度器持久化精确预留设备插件实现该预留设备插件用运行时身份丰富记录对账使受管硬件向活跃预留收敛。每一步有一个权威、一个持久交接物。这种分离让放置策略独立于 NVML 变更同时共享同一分配身份。DecodeMigAllocations的运行时身份必须全有或全无校验mig_allocations.go是这套模型的一致性兜底出现部分身份即拒绝宁可失败也不猜测。运维模型模式选择与工作负载接入节点级设备插件配置选择mig运行模式operatingmode对照 values.yaml 中 hami-core/mig 等模式示例另有migstrategy字段与 GPU Operator 的 migStrategy 语义对接见 values.yaml集群策略通过device-config.content或外部 ConfigMap 配置migProfileAllowlistvalues.yaml 注释示例RTX 6000 Ada→[1g.6gb, 2g.12gb, 4g.24gb]工作负载级Pod 通过nvidia.com/vgpu-mode: mig注解选择 MIG 分配源码常量见 device.goMigMode migGPU Operator 继续提供 NVIDIA 驱动与容器运行时路径。最小 MIG 工作负载examples/nvidia/dynamic_mig_example.yaml## This example will allocate 2g.10gb * 2 for A100-40GB-PCIE device ## or 1g.10gb * 2 for A100-80GB-XSM device. apiVersion: v1 kind: Pod metadata: name: gpu-pod annotations: nvidia.com/vgpu-mode: mig hami.io/gpu-scheduler-policy: binpack #(Optional) spec: containers: - name: ubuntu-container image: ubuntu:18.04 command: [bash, -c, sleep 86400] resources: limits: nvidia.com/gpu: 2 nvidia.com/gpumem: 8000该示例只验证资源分配与设备注入生产金丝雀应使用带 CUDA/NVML 工具的可信镜像并运行真实 GPU 负载迁移文档给出了mig-canary工作负载模板与完整验证清单见 dynamic-mig-migration.md。可观测性焦点运维可见性围绕六个维度每 GPU 发现的 Profile 与放置调度器预留决策与容量压力GI/CI 实现与运行时身份分配对账活动与容量复用启动收养结果工作负载跨生命周期事件的 GPU 进度。端到端验证使用跨混合 Profile 的持续 CUDA 负载、容量饱和、工作负载替换、设备插件重启与突发分配UUID 稳定性与持续的 GPU 进度共同证明生命周期连续性。演进方向架构为以下扩展提供了稳定扩展点可插拔的放置策略节点级碎片评分放置感知的调度器指标事件驱动的生命周期加速动态 MIG 身份的 CDI 同步更丰富的多 GPU 与异构节点验证。能力契约、预留契约与硬件归属边界是这些扩展的共同基础。决策总结动态 MIG 把硬件拓扑视为节点拥有的能力把放置视为调度器预留把 GI/CI 变更视为设备插件职责。Pod 元数据在控制面与运行时之间携带分配身份。这一模型为 HAMi 提供了确定性、拓扑感知的动态 MIG 调度与生命周期管理基础——日常 Profile 混合调度与实例回收不再依赖整卡几何切换而硬件约束切片被占后无法原位转换为重叠布局、MIG 模式切换与驱动维护仍需 drain/reboot始终由 NVIDIA MIG 本身决定。相关参考动态 MIG 架构本文主题从几何模板/MIG Manager 迁移到动态 MIGMPS 与 MIG 动态切片插件legacy 设计调度器侧共享类型定义预留注解编解码与校验Profile 选择与放置规划Profile 偏好注解实现设备插件 MIG 实例管理器Helm 配置示例MIG 工作负载示例【免费下载链接】HAMiHeterogeneous GPU Sharing on Kubernetes项目地址: https://gitcode.com/GitHub_Trending/ha/HAMi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考