Volcano vGPU 调度实战:HAMI-core 与 Dynamic MIG 双模式 GPU 共享方案详解
【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano
本文以 Volcano 官方用户指南docs/user-guide/how_to_use_volcano_vgpu.md为核心,系统讲解 Volcano vGPU(虚拟 GPU)调度的两种共享模式——HAMI-core 软件切片与 Dynamic MIG 硬件切片的完整落地方案。读完后你将掌握:vGPU 调度环境的安装与校验方法、deviceshare调度插件的全部关键参数、volcano.sh/vgpu-*系列资源与注解的使用方式,以及 PodGroup 设备打散、按 UUID 选卡、GPU 独占等进阶策略在调度器源码中的真实实现机制。
两种 vGPU 共享模式:HAMI-core 与 Dynamic MIG
Volcano 为虚拟 GPU(vGPU)调度提供两种 GPU 共享模式,两者在隔离层级与适用场景上差异明显:
1. HAMI-core(软件级 vGPU)
通过VCUDA(CUDA API 劫持)技术强制限制 GPU 核心与显存用量,实现软件层面的虚拟 GPU 切片。适用于需要细粒度 GPU 共享的环境,兼容所有 GPU 型号。
2. Dynamic MIG(硬件级 GPU 切片)
利用 NVIDIAMIG(Multi-Instance GPU)技术,将物理 GPU 切分为多个隔离实例,提供硬件级的性能保障。适用于性能敏感型负载,要求 GPU 支持 MIG(如 A100、H100)。
GPU 共享模式是节点级配置。Volcano 支持异构集群——即一部分节点使用 HAMI-core,另一部分节点使用 Dynamic MIG。节点模式的声明与 MIG geometry 配置由外部组件volcano-vgpu-device-plugin(Project-HAMi 生态项目)负责,本文聚焦 Volcano 调度器侧的实现。
从源码结构看,调度器通过注册表机制为不同模式装配不同的“共享处理器”:sharing_factory.go 定义了SharingFactory接口(TryAddPod/AddPod/SubPod),各模式通过init()中的RegisterFactory(mode, factory)注册;模式常量(hami-core、mig、mps)定义在 type.go 中。
安装与部署
通用前提条件
启用 vGPU 调度需满足以下环境前提(以官方文档为准):
- NVIDIA 驱动 > 440
- nvidia-docker > 2.0
- Docker 配置
nvidia为默认 runtime - Kubernetes >= 1.16
- Volcano >= 1.9
部署步骤:
- 按照 Volcano 安装指南部署 Volcano 各组件;
- 部署
volcano-vgpu-device-pluginDevice Plugin——该组件的 YAML 同时包含Node GPU 模式与MIG geometry的配置项,配置细节见该项目的 config 文档; - 校验节点可分配资源:
kubectl get node {node-name} -o yaml节点 Allocatable 中应出现如下 vGPU 资源:
volcano.sh/vgpu-memory: "89424" volcano.sh/vgpu-number: "8"源码佐证:调度器侧 device_info.go 的NewGPUDevices正是依赖这两个信号识别节点——它首先检查节点注解volcano.sh/node-vgpu-register(设备信息注册数据),然后要求volcano.sh/vgpu-number、volcano.sh/vgpu-cores、volcano.sh/vgpu-memory三类可分配资源均存在且非零,任一缺失则该节点不注册 vGPU 设备。资源名常量集中定义在 config/vgpu.go。
更新调度器配置
编辑volcano-scheduler-configmap,启用deviceshare插件的 vGPU 能力:
kind: ConfigMap apiVersion: v1 metadata: name: volcano-scheduler-configmap namespace: volcano-system data: volcano-scheduler.conf: | actions: "enqueue, allocate, backfill" tiers: - plugins: - name: predicates - name: deviceshare arguments: deviceshare.VGPUEnable: true # 启用 vgpu 插件 deviceshare.SchedulePolicy: binpack # 调度策略:binpack / spreaddeviceshare插件支持的全部 arguments 在 deviceshare.go 中定义,整理如下:
| 参数 | 类型 | 说明 |
|---|---|---|
deviceshare.VGPUEnable | bool | 启用 vGPU(HAMi vGPU)调度,本文主题参数 |
deviceshare.SchedulePolicy | string | 设备级调度策略,binpack或spread |
deviceshare.ScheduleWeight | int | 设备打分在节点排序中的权重,>0 时生效 |
deviceshare.GPUExclusiveRules | []labels | GPU 独占规则,见后文“GPU 独占”一节 |
deviceshare.KnownGeometriesCMName | string | MIG geometry ConfigMap 名,默认volcano-vgpu-device-config |
deviceshare.KnownGeometriesCMNamespace | string | 该 ConfigMap 所在命名空间,默认kube-system |
deviceshare.GPUSharingEnable/deviceshare.GPUNumberEnable/deviceshare.NodeLockEnable | bool | 与旧版 GPU 共享、GPU 整卡模式或节点锁相关的开关 |
源码中的关键校验逻辑(deviceshare.go 的enablePredicate):
- 若同时启用
GPUSharingEnable与GPUNumberEnable,调度器直接klog.Fatal——两者互斥; - 若
GPUSharingEnable/GPUNumberEnable与VGPUEnable同时为 true,调度器同样直接退出:gpushare(旧版整卡共享)与 vgpu 不能混用,升级 vGPU 方案前务必清理旧配置; VGPUEnable为 true 时,注册设备名为hamivgpu的设备(type.go 中DeviceName = "hamivgpu"),MIG geometry 默认从kube-system命名空间的volcano-vgpu-device-configConfigMap 读取(该 ConfigMap 由 volcano-vgpu-device-plugin 生成初始值,可自定义)。
HAMI-core 模式使用
在 Pod 中通过注解显式声明 HAMI-core 模式,并在resources.limits中申请 vGPU 资源:
metadata: name: hami-pod annotations: volcano.sh/vgpu-mode: "hami-core" spec: schedulerName: volcano containers: - name: cuda-container image: nvidia/cuda:9.0-devel resources: limits: volcano.sh/vgpu-number: 1 # 申请 1 张(虚拟)GPU 卡 volcano.sh/vgpu-cores: 50 # (可选)每块 vGPU 使用 50% 算力 volcano.sh/vgpu-memory: 3000 # (可选)每块 vGPU 使用 3GB 显存vGPU 资源项语义(常量见 config/vgpu.go):
| 资源名 | 含义 | 说明 |
|---|---|---|
volcano.sh/vgpu-number | 虚拟 GPU 卡数量 | 必选 |
volcano.sh/vgpu-memory | 每张 vGPU 的显存上限(MB) | 可选,不指定时按设备插件配置中的defaultMemory处理 |
volcano.sh/vgpu-cores | 每张 vGPU 的算力百分比(0–100) | 可选 |
volcano.sh/vgpu-memory-percentage | 显存百分比形式 | 源码中另支持的百分比写法 |
分配成功后,调度器会向 Pod 注入一组绑定注解(device_info.go 的Allocate):volcano.sh/vgpu-ids-new(实际分配的设备 UUID 列表)、volcano.sh/vgpu-node、volcano.sh/vgpu-time、volcano.sh/devices-to-allocate、volcano.sh/bind-phase等。这些注解随 Binding 请求由 apiserver 与节点分配原子合并,供设备插件在 bind 阶段完成容器级注入;回滚路径(UnAllocate)时Release会清理这些注解,但若bind-phase已为success则交给设备插件接管,调度器不再重复清理。
Dynamic MIG 模式使用
启用 MIG
在 GPU 节点上执行:
sudo nvidia-smi -mig 1Geometry 配置(可选)
volcano-vgpu-device-plugin会自动生成初始 MIG 配置,写入kube-system命名空间的volcano-vgpu-device-configConfigMap,可按需修改。该 ConfigMap 中的数据结构在调度器侧对应 config/vgpu.go:AllowedMigGeometries(按 GPU 型号列出allowedGeometries)、Geometry(一个分组内的geometries实例列表)、MigTemplate(如1g.10gb及其显存与数量)。
Pod 示例
metadata: name: mig-pod annotations: volcano.sh/vgpu-mode: "mig" spec: schedulerName: volcano containers: - name: cuda-container image: nvidia/cuda:9.0-devel resources: limits: volcano.sh/vgpu-number: 1 volcano.sh/vgpu-memory: 3000注意:实际分配的显存取决于 best-fit 命中的 MIG 切片规格(例如申请 3GB 可能命中 5GB 的切片)。
源码佐证:MIG 模式由 mig.go 中的MIGFactory实现。TryAddPod先按GPUMemoryFactor放大请求显存(默认 1 时不放大),再调用findMatch在该卡的MigTemplate/MigUsage中做 best-fit 匹配;命中后按切片实际显存更新UsedNum/UsedMem。这与文档“3GB 请求 → 5GB 切片”的行为完全对应。
进阶调度策略
PodGroup 设备打散(Spread)
为防止同一 PodGroup 内的两个 Pod 挤在同一块 vGPU 上,可为 Pod 添加注解volcano.sh/vgpu-podgroup-policy: spread;未加注解的 Pod 仍走默认 binpack 行为。
metadata: name: spread-pod annotations: volcano.sh/vgpu-podgroup-policy: "spread"注解常量定义在 type.go,判断逻辑在 utils.go:当注解值等于spread时启用组内打散;集成测试见 spread_integration_test.go。
按 UUID 选择物理 GPU
volcano.sh/vgpu-use-gpuuuid:物理 GPU UUID 的白名单,逗号分隔;volcano.sh/vgpu-nouse-gpuuuid:黑名单。
metadata: annotations: volcano.sh/vgpu-use-gpuuuid: "GPU-03f69c50-207a-2038-9b45-23cac89cb67d"metadata: annotations: volcano.sh/vgpu-nouse-gpuuuid: "GPU-03f69c50-207a-2038-9b45-23cac89cb67d"匹配语义(utils.go 的parseGPUUUIDList):UUID 去除首尾空白后精确匹配;若白名单中没有任何设备能满足请求,Pod 将保持不可调度;同一 UUID 同时出现在两个注解中时,黑名单优先。边界行为(空串、连续逗号、非法 UUID 报错等)由 utils_test.go 的单测覆盖。
GPU 独占(仅 HAMI-core 节点)
GPU 独占保证:匹配配置标签规则的 Pod 获得独占的物理 GPU——其他匹配规则的 Pod 不能与其共享同一块卡;不匹配规则的 Pod 仍可正常共享 GPU。该特性仅作用于 hami-core 节点:Dynamic MIG 节点本身已有硬件隔离,源码会直接跳过(gpuexclusive.go 中仅当Mode为空或hami-core时才包装)。
它与spread调度策略正交,可以叠加使用:spread是跨节点的负载均衡(把 Pod 分散到不同节点),而 GPU 独占是单节点内 GPU 设备粒度的互斥。若某节点所有 GPU 均被其他规则匹配 Pod 预留,该 Pod 会在此节点FilterNode 失败并保持 Pending,直到出现有空闲独占 GPU 的节点。
配置方式——在 deviceshare 插件参数中加入deviceshare.GPUExclusiveRules:
- name: deviceshare arguments: deviceshare.VGPUEnable: true deviceshare.GPUExclusiveRules: - workloadType: training - workloadType: batch priority: high每条规则是一组 label 键值对,Pod 必须同时匹配规则内全部标签才获得独占权;独占性只在同一条规则内部强制——匹配不同规则的 Pod 之间仍可共享 GPU。
Pod 示例:
metadata: name: training-job labels: workloadType: training spec: schedulerName: volcano containers: - name: trainer image: nvidia/cuda:12.0-base resources: limits: volcano.sh/vgpu-number: "4" volcano.sh/vgpu-memory: "16384"源码机制(gpuexclusive.go):
loadGPUExclusiveConfig+parseExclusiveRules将 YAML 规则解析为exclusiveRule{labels}切片;matchingRules按“全标签匹配”返回命中的规则下标;- 每个调度会话开始时,
wrapGPUDevicesForExclusivity把各节点的*vgpu.GPUDevices包装为exclusiveGPUDevices,并从三个来源重建“规则 → 已占 GPU”映射:设备 PodMap、Pod 的分配注解、上一调度周期的持久化状态(persistedGPUs/persistedPodRules跨会话保存,保证独占状态不因调度轮次结束丢失); - 核心手法是
capGPUs:临时将被规则预留的 GPU 的Number置为UsedNum(即“剩余虚拟卡数为 0”),使底层 vGPU 分配器自然跳过这些卡,调用结束后再由restoreGPUs还原——FilterNode与Allocate两个阶段均采用该机制,从而在不改动底层分配器的前提下实现设备级互斥。
调度器模式选择与调用链
显式模式与自动模式
- 显式模式:通过注解
volcano.sh/vgpu-mode(取值hami-core/mig)强制指定模式; - 自动模式:注解缺省时,调度器基于资源适配度与策略自动选择模式;
- 调度策略:
binpack倾向“剩余显存越少越好”(聚合碎片),spread倾向“空闲卡优先于共享卡”,两者均影响节点/设备打分(策略常量与语义见 type.go)。
调度器侧调用链
从 deviceshare.go 的OnSessionOpen可以还原完整调用链:
wrapGPUDevicesForExclusivity:若配置了独占规则,先对节点设备做独占包装(必须早于后续注册,保证整轮调度使用包装后的设备);- 注册PredicateFn:对每个请求了 vGPU 的 Task 调用
dev.FilterNode(task.Pod, schedulePolicy)(内部即 device_info.go 的checkNodeGPUSharingPredicateAndScore),不满足设备容量/模式/UUID 约束的节点直接淘汰; - 注册NodeOrderFn:当
deviceshare.ScheduleWeight > 0时,用 Filter 阶段缓存的设备打分(ScoreNode直接返回缓存值以避免重复计算)参与节点排序; - Allocate阶段再次执行设备校验并写分配注解,随 Binding 下发。
模式对比与监控
模式对比总表
| 模式 | 隔离级别 | 是否要求 MIG GPU | 是否需要注解 | 核心/显存控制 | 推荐场景 |
|---|---|---|---|---|---|
| HAMI-core | 软件(VCUDA) | 否 | 否(可选) | 是 | 通用负载 |
| Dynamic MIG | 硬件 | 是 | 是 | 由 MIG 切片决定 | 性能敏感型作业 |
监控
- 调度器指标:
curl http://<volcano-scheduler-ip>:8080/metrics- 设备插件指标:
curl http://<plugin-pod-ip>:9394/metrics指标涵盖 GPU 利用率、Pod 显存用量与上限等;调度器侧的指标埋点在 metrics.go 中,随AddPod/SubPod逐卡更新。
延伸阅读
- 插件实现入口:deviceshare.go、GPU 独占:gpuexclusive.go
- vGPU 设备模型:device_info.go、资源与注解常量:type.go、MIG 分配逻辑:mig.go
- MIG geometry 配置结构:config/vgpu.go
- 相关测试:deviceshare_test.go、gpuexclusive_test.go、spread_integration_test.go、mig_test.go
- 设备插件侧(节点模式与 MIG geometry 配置)请参考
volcano-vgpu-device-plugin项目的安装与配置文档
【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考