Skip to main content

Volcano原生支持HAMi vGPU,但需要启用对应的deviceshare 插件。

1. Volcano调度器配置

具体配置如下:

volcano-scheduler.conf
actions: "enqueue, allocate, backfill"
tiers:
- plugins:
- name: priority
- name: gang
- name: conformance
- plugins:
- name: drf
- name: deviceshare
arguments:
# 是否启用vgpu特性
deviceshare.VGPUEnable: true
# volcano-vgpu-device-config这个ConfigMap对应的命名空间
# 便于调度器自动读取ConfigMap内容
deviceshare.KnownGeometriesCMNamespace: volcano-system
- name: predicates
- name: proportion
- name: nodeorder
- name: binpack

同时需要替换NVIDIA Device Pluginhttps://github.com/Project-HAMi/volcano-vgpu-device-plugin ,具体参考:https://project-hami.io/zh/docs/userguide/volcano-vgpu/NVIDIA-GPU/how-to-use-volcano-vgpu

2. Volcano vGPU执行流程

Volcano + HAMi vGPU的完整执行流程涉及多个组件的协同工作,从Pod创建到最终运行在节点上,经历了以下关键步骤:

2.1 组件交互概要

以下是Volcano vGPU资源使用的大致交互时序图,包含了关键的几个组件之间的交互。

2.2 详细交互流程

以下是通过梳理Volcanovolcano-vgpu-device-plugin源码得到的完整执行流程。

2.2.1 阶段1:Pod创建

  1. 用户创建Pod
    apiVersion: v1
    kind: Pod
    metadata:
    name: vgpu-test
    spec:
    schedulerName: volcano # 指定使用 Volcano 调度器
    containers:
    - name: cuda-app
    image: nvidia/cuda:11.0-base
    resources:
    limits:
    volcano.sh/vgpu-number: 2 # 请求 2 张 GPU 卡
    volcano.sh/vgpu-memory: 3000 # (可选)每个 vGPU 使用 3G 显存
    volcano.sh/vgpu-cores: 50 # (可选)每个 vGPU 使用 50% 核心

2.2.2 阶段2:调度器调度

  1. Volcano Scheduler接收调度请求

    • SchedulerAPI Server获取待调度的Pod
    • 初始化调度会话(Session),注册deviceshare插件的预选和打分函数
  2. deviceshare插件预选(Predicate)

    核心逻辑deviceshare.go:125-162):

    // 遍历所有注册的设备类型(vGPU/GPU-Share等)
    for _, val := range api.RegisteredDevices {
    if dev, ok := node.Others[val].(api.Devices); ok {
    // 调用vGPU的FilterNode方法
    code, msg, err := dev.FilterNode(task.Pod, dp.schedulePolicy)
    if err != nil {
    return api.NewFitErrWithStatus(task, node, predicateStatus...)
    }
    }
    }

    vGPU预选检查device_info.go:247-259):

    • 调用checkNodeGPUSharingPredicateAndScore函数执行资源匹配
    • 检查节点Annotation中的设备注册信息(volcano.sh/node-vgpu-register
    • 遍历节点所有GPU设备,逐一检查是否满足Pod请求:
      • 显存是否充足:device.Memory - device.UsedMem >= request.Memreq
      • 算力是否充足:device.UsedCore + request.Coresreq <= 100
      • 设备类型是否匹配(NVIDIA/AMD/昇腾等)
      • 独占模式检查:Coresreq=100时设备不能被其他Pod占用
    • 将匹配结果缓存到gs.Score,避免打分阶段重复计算
  3. deviceshare插件打分(Score)

    核心逻辑deviceshare.go:164-179):

    // 计算节点设备得分
    score, status := getDeviceScore(context.TODO(), task.Pod, node, dp.schedulePolicy)
    nodeScore = float64(score) * float64(dp.scheduleWeight)

    vGPU打分策略utils.go:440-453):

    • binpack模式score = 10 * (UsedMem / TotalMem),优先选择资源使用率高的节点
    • spread模式score = 10(仅当设备已被1Pod使用时),优先选择资源分散的节点
    • 直接返回预选阶段缓存的gs.Score,无需重复计算
  4. 调度决策与资源分配

    Allocate阶段device_info.go:261-295):

    • 选择得分最高的节点
    • 调用Allocate方法执行资源分配
    • 更新Pod Annotation,记录分配的设备信息:
      volcano.sh/vgpu-node: dev-app-2-150-master-1
      volcano.sh/vgpu-time: "18446744073709551615"
      volcano.sh/vgpu-ids-new: 'GPU-uuid1,NVIDIA,3000,50:GPU-uuid2,NVIDIA,3000,50:'
      volcano.sh/bind-phase: allocating
    • Pod绑定到目标节点

2.2.3 阶段3:Device Plugin分配

  1. Device Plugin Allocateplugin.go:416-515

    核心逻辑

    • Kubelet检测到Pod被调度到本节点,调用Allocate方法
    • Pod Annotation读取Volcano分配的设备信息(volcano.sh/vgpu-ids-new
    • 注入容器环境变量(plugin.go:460-476):
      // 设置GPU可见性
      response.Envs["NVIDIA_VISIBLE_DEVICES"] = strings.Join(m.GetContainerDeviceStrArray(devreq), ",")
      // 为每个vGPU设置显存限制
      for i, dev := range devreq {
      limitKey := fmt.Sprintf("CUDA_DEVICE_MEMORY_LIMIT_%v", i)
      response.Envs[limitKey] = fmt.Sprintf("%vm", dev.Usedmem*int32(config.GPUMemoryFactor))
      }
      // 设置算力限制(如果Pod未指定volcano.sh/vgpu-cores,则为0,表示不限制算力)
      response.Envs["CUDA_DEVICE_SM_LIMIT"] = fmt.Sprint(devreq[0].Usedcores)
    • 挂载vGPU库和配置文件(plugin.go:485-508):
      • /usr/local/vgpu/libvgpu.soCUDA API劫持库
      • /etc/ld.so.preload:预加载配置(内容为/usr/local/vgpu/libvgpu.so
      • /tmp/vgpu:缓存目录
      • /tmp/vgpulock:进程锁目录
    • 返回ContainerAllocateResponseKubelet

2.2.4 阶段4:容器启动

  1. Container Runtime处理

    • Kubelet将环境变量和挂载信息传递给容器运行时
    • 挂载GPU设备文件(/dev/nvidia*
    • 挂载NVIDIA驱动库,并设置LD_LIBRARY_PATH环境变量
    • 挂载/etc/ld.so.preload文件(内容为/usr/local/vgpu/libvgpu.so
    • 容器启动时,动态链接器读取/etc/ld.so.preload文件,强制预加载libvgpu.so
    • libvgpu.so从环境变量读取CUDA_DEVICE_MEMORY_LIMIT_*CUDA_DEVICE_SM_LIMIT,初始化资源限制

    注意:这里使用的是/etc/ld.so.preload文件而非LD_PRELOAD环境变量。通过env命令看不到LD_PRELOAD,但可以通过cat /etc/ld.so.preload查看预加载配置。

    两种预加载机制对比:

    特性/etc/ld.so.preload文件LD_PRELOAD环境变量
    类型配置文件环境变量
    env可见❌ 不可见✅ 可见
    查看方式cat /etc/ld.so.preloadecho $LD_PRELOAD
    作用范围系统级,所有进程进程级,继承环境变量
    Volcano vGPU✅ 使用❌ 不使用
    HAMI独立部署❌ 不使用✅ 使用

2.2.5 阶段5:应用运行

  1. CUDA API劫持与资源限制

    应用调用 cuMemAlloc(3000MB)

    libvgpu.so 劫持(通过 /etc/ld.so.preload)

    检查 CUDA_DEVICE_MEMORY_LIMIT_0=3000m(显存限制)

    检查 CUDA_DEVICE_SM_LIMIT=50(算力限制)

    调用真实 CUDA Driver API

    返回结果给应用

3. Volcano vGPU与HAMi独立部署的区别

对比项独立HAMiVolcano + HAMi
调度器Kubernetes Default Scheduler + HAMi Scheduler ExtenderVolcano Scheduler
WebhookHAMi Mutating WebhookVolcano Mutating Webhook
资源名称nvidia.com/gpunvidia.com/gpumemvolcano.sh/vgpu-numbervolcano.sh/vgpu-memory
调度插件Scheduler Extender(外部扩展)deviceshare Plugin(内置插件)
设备分配HAMi Device Pluginvolcano-vgpu-device-plugin
环境变量注入Webhook注入Device Plugin Allocate注入

4. Volcano vGPU监控指标

Volcano Scheduler在调度vGPU资源时会暴露Prometheus监控指标,用于观测GPU设备的分配和使用情况。这些指标定义在 pkg/scheduler/api/devices/nvidia/vgpu/metrics.go 中。

4.1 设备级指标

指标名称类型标签说明单位
volcano_vgpu_device_memory_limitGaugedevID, NodeNameGPU卡的总显存容量MB
volcano_vgpu_device_allocated_memoryGaugedevID, NodeNameGPU卡已分配的显存总量MB
volcano_vgpu_device_allocated_coresGaugedevID, NodeNameGPU卡已分配的算力百分比% (0-100)
volcano_vgpu_device_shared_numberGaugedevID, NodeName共享此 GPU卡的Pod数量

4.2 Pod 级指标

指标名称类型标签说明单位
volcano_vgpu_device_memory_allocation_for_a_certain_podGaugedevID, NodeName, podName特定Pod在此GPU卡上分配的显存MB
volcano_vgpu_device_core_allocation_for_a_certain_podGaugedevID, NodeName, podName特定Pod在此GPU卡上分配的算力% (0-100)

4.3 常用 PromQL 查询示例

  1. 查看节点上所有 GPU 卡的显存使用率

    volcano_vgpu_device_allocated_memory / volcano_vgpu_device_memory_limit * 100
  2. 查看 GPU 卡的平均共享数

    avg(volcano_vgpu_device_shared_number) by (NodeName)
  3. 查看特定节点上 GPU 算力分配情况

    volcano_vgpu_device_allocated_cores{NodeName="node-1"}
  4. 查看特定 Pod 的 GPU 显存分配

    volcano_vgpu_device_memory_allocation_for_a_certain_pod{podName="my-training-pod"}
  5. 统计集群中 GPU 卡的总显存利用率

    sum(volcano_vgpu_device_allocated_memory) / sum(volcano_vgpu_device_memory_limit) * 100

4.4 指标访问方式

Volcano Scheduler默认在 :8080/metrics 端点暴露Prometheus监控指标。可以通过以下方式访问:

# 直接访问 Scheduler Pod
kubectl port-forward -n volcano-system svc/volcano-scheduler 8080:8080
curl http://localhost:8080/metrics | grep volcano_vgpu

# 或配置 Prometheus 自动采集
# 在 Prometheus 配置中添加 Volcano Scheduler 的 ServiceMonitor

4.5 指标参考数据

指标文件:volcano-vgpu-metrics.txt