HAMi + Volcano 联合测试:在单节点 Kubernetes 上使用 RTX 3070 Ti 验证 vGPU 与 Gang Scheduling
一、测试背景
最近在学习 HAMi、Volcano 以及 GPU 共享调度相关内容。单独看 HAMi,它主要解决 GPU 细粒度共享和容器内 GPU 资源限制的问题;单独看 Volcano,它主要增强 Kubernetes 的批处理调度能力,例如 Queue、PodGroup、Gang Scheduling 等。
在 AI 训练、推理或者批处理任务里,这两个能力经常会同时出现:
-
GPU 资源不一定每次都要整卡分配,小任务可能只需要一部分显存和算力;
-
分布式训练或者多 worker 任务不能只启动一部分 Pod,否则已经启动的 Pod 也可能一直等待;
-
多个任务之间还需要通过队列做资源划分和调度控制。
这篇文章记录一次 HAMi + Volcano vGPU 联合测试,重点验证下面几个内容:
-
Volcano vGPU 的基本使用;
-
单张 GPU 上运行多个 vGPU Pod;
-
VolcanoJob 配合 vGPU 做 Gang Scheduling;
-
资源不足时 PodGroup 的状态变化;
-
Queue 对 vGPU 资源的限制效果。
我的测试环境如下:
| 项目 | 配置 |
|---|---|
| Kubernetes | 单节点集群 |
| GPU | NVIDIA RTX 3070 Ti |
| 显存 | 8G |
| 调度器 | Volcano |
| GPU 共享方式 | Volcano vGPU + HAMi-core |
| 测试命名空间 | volcano-demo |
这里使用的是 Volcano vGPU 里的 HAMI-core 模式,也就是软件 vGPU。容器内看到的 GPU 显存和 core 会受到 HAMi-core 限制。
二、先分清普通 HAMi 和 Volcano vGPU
做实验之前,一定要先把两条路线分清楚,否则很容易把资源名、调度器和 device plugin 混在一起。
1. 普通 HAMi 路线
普通 HAMi 常见资源名是:
resources:
limits:
nvidia.com/gpu: 1
nvidia.com/gpumem: 3000
nvidia.com/gpucores: 50
或者:
nvidia.com/gpumem-percentage
普通 HAMi 主要依赖 HAMi 自己的 scheduler、webhook、device plugin、HAMi-core 等组件。它的核心能力是 GPU 共享、显存限制、core 限制和设备感知调度。
如果走普通 HAMi 路线,不建议随便把 Pod 写成:
schedulerName: volcano
因为这样会让 Pod 进入 Volcano Scheduler 的调度流程,行为就不再是普通 HAMi 的调度逻辑。
2. Volcano vGPU 路线
本文走的是 Volcano vGPU 路线:
Volcano Scheduler + volcano-vgpu-device-plugin + HAMi-core
这条路线里,Pod 使用的是 Volcano vGPU 资源名:
volcano.sh/vgpu-number
volcano.sh/vgpu-memory
volcano.sh/vgpu-cores
也就是说,本文不是安装普通 HAMi Helm Chart,然后强行把普通 HAMi Pod 指定给 Volcano 调度。
在 Volcano vGPU 方案里:
| 组件 | 作用 |
|---|---|
| Volcano Scheduler | 负责调度、Gang Scheduling、Queue 资源管理 |
| deviceshare 插件 | 让 Volcano 识别并调度设备共享资源 |
| volcano-vgpu-device-plugin | 向 kubelet 注册 vGPU 资源,并处理设备分配 |
| HAMi-core | 在容器内限制 GPU 显存和 core 使用 |
| Pod / VolcanoJob | 通过 volcano.sh/vgpu-* 申请 vGPU 资源 |
三、实验前提
Kubernetes 集群需要正常运行:
kubectl get node -o wide
我的环境是单节点:
NAME STATUS ROLES AGE VERSION
master-01 Ready control-plane 10d v1.xx.x
节点上的 NVIDIA 驱动也需要正常:
nvidia-smi
能正常看到 GPU信息 即可。
本文所有 YAML 默认使用 volcano-demo 命名空间。实验前提前准备好命名空间:
kubectl create ns volcano-demo
四、部署并配置 Volcano vGPU
如果已经安装过 Volcano,可以先确认 Volcano 组件是否正常:
kubectl get pod -n volcano-system
正常情况下可以看到类似组件:
volcano-admission
volcano-controllers
volcano-scheduler
同时确认 Queue:
kubectl get queue
一般 Volcano 安装后会自动创建 default 队列。后面的 VolcanoJob 如果没有额外指定队列,也可以使用这个默认队列。
Volcano vGPU 需要在 Volcano Scheduler 里开启 deviceshare 插件,并启用 vGPU:
deviceshare.VGPUEnable: true
编辑 Volcano Scheduler 的 ConfigMap:
kubectl edit cm -n volcano-system volcano-scheduler-configmap
配置示例如下:
apiVersion: v1
kind: ConfigMap
metadata:
name: volcano-scheduler-configmap
namespace: volcano-system
data:
volcano-scheduler.conf: |
actions: "enqueue, allocate, backfill"
tiers:
- plugins:
- name: priority
- name: gang
- name: conformance
- plugins:
- name: drf
- name: deviceshare
arguments:
deviceshare.VGPUEnable: true
- name: predicates
- name: proportion
- name: nodeorder
- name: binpack
这里重点是 deviceshare:
- name: deviceshare
arguments:
deviceshare.VGPUEnable: true
deviceshare 用于让 Volcano 参与设备共享资源的调度。deviceshare.VGPUEnable: true 表示开启 vGPU 调度能力。
修改完成后重启 Volcano Scheduler:
kubectl rollout restart deployment -n volcano-system volcano-scheduler
kubectl get pod -n volcano-system
然后部署 volcano-vgpu-device-plugin:
kubectl create -f https://raw.githubusercontent.com/Project-HAMi/volcano-vgpu-device-plugin/main/volcano-vgpu-device-plugin.yml
默认会部署到 kube-system 命名空间。查看 DaemonSet:
kubectl get ds -n kube-system | grep volcano
查看 Pod:
kubectl get pod -n kube-system -o wide | grep volcano-device-plugin
正常情况下可以看到 volcano-device-plugin Pod 运行在 GPU 节点上。
安装完成后,需要检查节点上是否已经出现 volcano.sh/vgpu-* 资源:
kubectl get node <你的节点名> -o yaml | grep -A30 "capacity:" | grep volcano.sh
kubectl get node <你的节点名> -o yaml | grep -A30 "allocatable:" | grep volcano.sh
正常情况下可以看到类似资源:
volcano.sh/vgpu-number: "10"
volcano.sh/vgpu-memory: "8192"
volcano.sh/vgpu-cores: "100"
实际显示值以你的环境为准。
这里要注意三点。
第一,volcano.sh/vgpu-number 不是物理 GPU 数量。我的机器只有一张 RTX 3070 Ti,但是 volcano.sh/vgpu-number 可能显示为 10。这是因为 device plugin 可以把一张物理 GPU 划分成多个 vGPU 份额。
第二,volcano.sh/vgpu-memory 以节点实际注册出来的资源为准。我的 RTX 3070 Ti 是 8G 显存,所以总的 volcano.sh/vgpu-memory 大概在 8G 左右。如果 Pod 申请:
volcano.sh/vgpu-memory: 2000
可以理解为这个容器申请大约 2G 的 vGPU 显存。
第三,后续 YAML 里的资源名必须和节点上实际注册出来的资源名保持一致。本文使用:
volcano.sh/vgpu-number
volcano.sh/vgpu-memory
volcano.sh/vgpu-cores
如果你的环境里资源名不同,就以 capacity 和 allocatable 看到的结果为准。
五、测试一:Volcano vGPU 单 Pod 测试
先从最简单的 Pod 开始验证,确认 Volcano vGPU 是否能正常给容器分配 vGPU 资源。
这个 Pod 申请 1 个 vGPU 份额、2000Mi 左右显存和 30% core:
apiVersion: v1
kind: Pod
metadata:
name: volcano-vgpu-single
namespace: volcano-demo
spec:
schedulerName: volcano
containers:
- name: cuda
image: nvidia/cuda:11.0.3-base-ubuntu18.04
imagePullPolicy: IfNotPresent
command:
- bash
- -lc
- |
echo "===== GPU ENV ====="
env | egrep 'CUDA_DEVICE|NVIDIA_VISIBLE_DEVICES|VGPU|VOLCANO' || true
echo "===== NVIDIA SMI ====="
nvidia-smi
sleep 3600
resources:
limits:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 2000
volcano.sh/vgpu-cores: 30
Pod 启动后,先进入容器查看和 CUDA/vGPU 相关的环境变量:
kubectl -n volcano-demo exec -it volcano-vgpu-single -- env | grep CUDA
输出如下:
NVIDIA_REQUIRE_CUDA=cuda>=11.0 brand=tesla,driver>=418,driver<419
NV_CUDA_CUDART_VERSION=11.0.221-1
NV_CUDA_COMPAT_PACKAGE=cuda-compat-11-0
CUDA_VERSION=11.0.3
CUDA_DEVICE_MEMORY_LIMIT_0=2000m
CUDA_DEVICE_SM_LIMIT=30
CUDA_DEVICE_MEMORY_SHARED_CACHE=/tmp/vgpu/6446d246-5917-419d-bdc3-1a119044f857.cache
这里重点看两个环境变量:
CUDA_DEVICE_MEMORY_LIMIT_0=2000m
CUDA_DEVICE_SM_LIMIT=30
CUDA_DEVICE_MEMORY_LIMIT_0=2000m 对应前面申请的:
volcano.sh/vgpu-memory: 2000
CUDA_DEVICE_SM_LIMIT=30 对应前面申请的:
volcano.sh/vgpu-cores: 30
也就是说,vGPU device plugin 已经把显存限制和 core 限制通过环境变量注入到了容器里。
继续在容器里执行 nvidia-smi:
kubectl exec -n volcano-demo -it volcano-vgpu-single -- nvidia-smi
输出如下:
[HAMI-core Msg(27:134137520396096:libvgpu.c:870)]: Initializing.....
Mon Jun 8 06:51:05 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.159.03 Driver Version: 580.159.03 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3070 Ti Off | 00000000:01:00.0 Off | N/A |
| N/A 51C P8 34W / 115W | 0MiB / 2000MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
[HAMI-core Msg(27:134137520396096:multiprocess_memory_limit.c:703)]: Cleanup on exit for PID 27
[HAMI-core Msg(27:134137520396096:multiprocess_memory_limit.c:739)]: Exit cleanup complete for PID 27
这段输出里可以看到两个现象。
第一,nvidia-smi 执行时出现了 HAMi-core 日志:
[HAMI-core Msg(...:libvgpu.c:870)]: Initializing.....
这说明容器内的 GPU 调用已经经过 HAMi-core。
第二,容器内看到的 GPU 显存不是物理卡完整的 8G,而是 2000MiB 左右:
0MiB / 2000MiB
这说明 volcano.sh/vgpu-memory: 2000 已经对容器内可见显存产生了限制。
这个单 Pod 测试主要验证的是:Volcano vGPU 资源能正常分配,HAMi-core 能正常生效,容器内能看到被限制后的 GPU 资源。
六、测试二:VolcanoJob + vGPU + Gang Scheduling
单 Pod 测试通过后,再测试 VolcanoJob。
VolcanoJob 更适合批处理任务或者多 worker 任务。它和普通 Pod 的区别在于,VolcanoJob 可以通过 minAvailable 表达 Gang Scheduling 语义,也就是多个 Pod 需要作为一个整体被调度。
下面这个 Job 创建 2 个 worker,每个 worker 申请 1 个 vGPU 份额、2000Mi 显存和 30% core:
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: vcjob-vgpu-gang
namespace: volcano-demo
spec:
schedulerName: volcano
queue: default
minAvailable: 2
maxRetry: 1
tasks:
- name: vgpu-worker
replicas: 2
template:
spec:
restartPolicy: Never
containers:
- name: cuda
image: nvidia/cuda:11.0.3-base-ubuntu18.04
imagePullPolicy: IfNotPresent
command:
- bash
- -lc
- |
echo "worker: $(hostname)"
echo "===== GPU ENV ====="
env | egrep 'CUDA_DEVICE|NVIDIA_VISIBLE_DEVICES|VGPU|VOLCANO' || true
echo "===== NVIDIA SMI ====="
nvidia-smi
sleep 3600
resources:
limits:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 2000
volcano.sh/vgpu-cores: 30
查看 VolcanoJob、PodGroup 和 Pod:
kubectl -n volcano-demo get vcjob
kubectl -n volcano-demo get podgroup
kubectl -n volcano-demo get pod
输出如下:
kubectl -n volcano-demo get vcjob
NAME STATUS MINAVAILABLE RUNNINGS AGE
vcjob-vgpu-gang Running 2 2 16s
kubectl -n volcano-demo get podgroup
NAME STATUS MINMEMBER RUNNINGS AGE
vcjob-vgpu-gang-9f87eec0-65ee-4c88-bc37-fe3c924c340e Running 2 2 24s
kubectl -n volcano-demo get pod
NAME READY STATUS RESTARTS AGE
vcjob-vgpu-gang-vgpu-worker-0 1/1 Running 0 27s
vcjob-vgpu-gang-vgpu-worker-1 1/1 Running 0 27s
这里可以看到:
-
VolcanoJob 状态是
Running; -
PodGroup 状态是
Running; -
两个 worker Pod 都已经运行起来。
进入其中一个 worker 查看 nvidia-smi:
kubectl exec -n volcano-demo -it vcjob-vgpu-gang-vgpu-worker-0 -- nvidia-smi
输出如下:
[HAMI-core Msg(16:140086174201664:libvgpu.c:870)]: Initializing.....
Mon Jun 8 06:56:38 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 580.159.03 Driver Version: 580.159.03 CUDA Version: 13.0 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 3070 Ti Off | 00000000:01:00.0 Off | N/A |
| N/A 49C P8 12W / 115W | 0MiB / 2000MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
[HAMI-core Msg(16:140086174201664:multiprocess_memory_limit.c:703)]: Cleanup on exit for PID 16
[HAMI-core Msg(16:140086174201664:multiprocess_memory_limit.c:739)]: Exit cleanup complete for PID 16
这个 Job 里有几个关键点:
| 字段 | 含义 |
|---|---|
schedulerName: volcano |
让这个 Job 下面的 Pod 交给 Volcano Scheduler 调度 |
queue: default |
让这个 Job 进入 Volcano 的 default 队列 |
tasks.replicas: 2 |
当前任务需要启动 2 个 worker |
minAvailable: 2 |
至少 2 个 worker 都满足调度条件时,这个 Job 才能整体运行 |
volcano.sh/vgpu-memory: 2000 |
每个 worker 申请约 2000Mi vGPU 显存 |
这次实验里,两个 worker 各申请 2000Mi 显存,总共约 4000Mi。我的 RTX 3070 Ti 是 8G 显存,所以这两个 worker 可以同时调度成功。
这里的重点不是“两个 Pod 能启动”这么简单,而是 Volcano 通过 PodGroup 表达了“这组 Pod 要作为一个整体调度”的语义。对于多 worker 任务来说,如果只启动一部分 worker,任务很可能无法正常工作,所以 Gang Scheduling 的意义就是保证任务组满足最小运行成员数后再整体运行。
七、测试三:Gang Scheduling 资源不足场景
接下来测试资源不足时的情况。
这次仍然创建 2 个 worker,但是把每个 worker 的显存申请改成 6000Mi。这样两个 worker 合计需要 12000Mi 显存,而我的 RTX 3070 Ti 只有 8G 显存,所以这个 Job 不应该被整体调度起来。
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: vcjob-vgpu-gang-insufficient
namespace: volcano-demo
spec:
schedulerName: volcano
queue: default
minAvailable: 2
maxRetry: 1
tasks:
- name: vgpu-worker
replicas: 2
template:
spec:
restartPolicy: Never
containers:
- name: cuda
image: nvidia/cuda:11.0.3-base-ubuntu18.04
imagePullPolicy: IfNotPresent
command:
- bash
- -lc
- |
echo "worker: $(hostname)"
nvidia-smi
sleep 3600
resources:
limits:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 6000
volcano.sh/vgpu-cores: 30
查看 PodGroup:
kubectl get podgroup -n volcano-demo
输出类似如下:
NAME STATUS MINMEMBER RUNNINGS AGE
vcjob-vgpu-gang-insufficient-xxxx Inqueue 2 68s
继续查看 PodGroup 详情:
kubectl describe podgroup -n volcano-demo <podgroup-name>
可以看到类似信息:
Status:
Conditions:
Message: 1/2 tasks in gang unschedulable: pod group is not ready, 2 Pending, 2 minAvailable; Pending: 1 Schedulable, 1 Unschedulable
Reason: NotEnoughResources
Type: Unschedulable
Phase: Inqueue
这段信息说明,当前 PodGroup 的 minAvailable 是 2,也就是至少要有 2 个 worker 同时满足调度条件,整个 Job 才能运行。
但是从调度结果看,当前资源无法同时满足 2 个 worker 的 vGPU 显存申请,所以 PodGroup 保持在 Inqueue 状态,两个 worker 也不会整体进入 Running。
这里需要注意 1 Schedulable, 1 Unschedulable 这句话。它表示从单个 Pod 的角度看,可能有一个 worker 的资源可以满足,但另一个 worker 的资源不满足。由于这个 Job 要求 minAvailable: 2,Volcano 不会只启动其中一个 worker,而是让整个 PodGroup 等待资源满足。
这就是 Gang Scheduling 的价值:资源不满足最小运行成员数时,整组任务等待,避免只启动一部分 Pod 造成资源浪费。
八、测试四:Queue 队列限制 vGPU 资源
前面的测试使用的是 default 队列。接下来创建一个专门的 GPU 队列,通过 Queue 的 capability 限制这个队列最多能使用多少资源。
gpu-small-queue.yaml:
apiVersion: scheduling.volcano.sh/v1beta1
kind: Queue
metadata:
name: gpu-small-queue
spec:
weight: 1
reclaimable: false
capability:
cpu: "2"
memory: "4Gi"
volcano.sh/vgpu-number: "2"
volcano.sh/vgpu-memory: "4000"
volcano.sh/vgpu-cores: "60"
这个队列的含义是:gpu-small-queue 最多可以使用 2 个 vGPU 份额、4000Mi vGPU 显存和 60% vGPU cores。
先提交一个在队列能力范围内的 VolcanoJob:
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: vcjob-vgpu-queue
namespace: volcano-demo
spec:
schedulerName: volcano
queue: gpu-small-queue
minAvailable: 2
tasks:
- name: vgpu-worker
replicas: 2
policies:
- event: TaskCompleted
action: CompleteJob
template:
spec:
restartPolicy: Never
containers:
- name: cuda
image: nvidia/cuda:11.0.3-base-ubuntu18.04
command: ["bash", "-lc", "nvidia-smi; sleep 60"]
resources:
limits:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 1000
volcano.sh/vgpu-cores: 30
这个 Job 有 2 个 worker,每个 worker 申请:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 1000
volcano.sh/vgpu-cores: 30
两个 worker 合计申请:
volcano.sh/vgpu-number: 2
volcano.sh/vgpu-memory: 2000
volcano.sh/vgpu-cores: 60
它没有超过 gpu-small-queue 的 capability:
volcano.sh/vgpu-number: "2"
volcano.sh/vgpu-memory: "4000"
volcano.sh/vgpu-cores: "60"
所以这个 Job 可以正常运行。
查看 Pod:
kubectl -n volcano-demo get pod
输出如下:
NAME READY STATUS RESTARTS AGE
vcjob-vgpu-queue-vgpu-worker-0 1/1 Running 0 7s
vcjob-vgpu-queue-vgpu-worker-1 1/1 Running 0 7s
接下来删掉上面的 Job,重新提交一个超出队列能力的 VolcanoJob。这个 Job 仍然是 2 个 worker,但是每个 worker 申请 3000Mi 显存:
apiVersion: batch.volcano.sh/v1alpha1
kind: Job
metadata:
name: vcjob-vgpu-queue
namespace: volcano-demo
spec:
schedulerName: volcano
queue: gpu-small-queue
minAvailable: 2
tasks:
- name: vgpu-worker
replicas: 2
policies:
- event: TaskCompleted
action: CompleteJob
template:
spec:
restartPolicy: Never
containers:
- name: cuda
image: nvidia/cuda:11.0.3-base-ubuntu18.04
command: ["bash", "-lc", "nvidia-smi; sleep 60"]
resources:
limits:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 3000
volcano.sh/vgpu-cores: 30
这个 Job 的总资源申请变成:
volcano.sh/vgpu-number: 2
volcano.sh/vgpu-memory: 6000
volcano.sh/vgpu-cores: 60
其中 volcano.sh/vgpu-memory: 6000 已经超过了 gpu-small-queue 里配置的:
volcano.sh/vgpu-memory: "4000"
所以这个 Job 不能在该队列下整体运行。
查看 Pod:
kubectl -n volcano-demo get pod
输出如下:
NAME READY STATUS RESTARTS AGE
vcjob-vgpu-queue-vgpu-worker-0 0/1 Pending 0 8s
vcjob-vgpu-queue-vgpu-worker-1 0/1 Pending 0 8s
查看 PodGroup:
kubectl -n volcano-demo get podgroup
输出如下:
NAME STATUS MINMEMBER RUNNINGS AGE
vcjob-vgpu-queue-3c251347-4dbd-4435-914a-f06dafb27742 Inqueue 2 14s
继续查看 PodGroup 详情:
kubectl -n volcano-demo describe podgroup vcjob-vgpu-queue-3c251347-4dbd-4435-914a-f06dafb27742
关键内容如下:
Spec:
Min Member: 2
Min Resources:
count/pods: 2
Pods: 2
Min Task Member:
Vgpu - Worker: 2
Queue: gpu-small-queue
Status:
Conditions:
Message: 1/2 tasks in gang unschedulable: pod group is not ready, 2 Pending, 2 minAvailable; Pending: 1 Schedulable, 1 Unschedulable
Reason: NotEnoughResources
Status: True
Type: Unschedulable
Phase: Inqueue
Events:
Type Reason From Message
---- ------ ---- -------
Warning Unschedulable volcano 0/0 tasks in gang unschedulable: pod group is not ready, 2 minAvailable
Warning Unschedulable volcano 2/2 tasks in gang unschedulable: pod group is not ready, 2 Pending, 2 minAvailable; Pending: 1 Schedulable, 1 Unschedulable
这次 PodGroup 里可以看到 Queue: gpu-small-queue,说明这个 Job 确实进入了我们创建的 GPU 队列。
同时,两个 worker 都保持 Pending,PodGroup 处于 Inqueue。原因是这个 Job 的两个 worker 加起来需要 6000Mi vGPU 显存,而 gpu-small-queue 的 capability 只允许 4000Mi。队列资源不满足 minAvailable: 2 的要求,所以 Volcano 不会让这组 worker 整体运行。
这个实验说明:Queue 的作用不是切 GPU,也不是替代 Pod 里的 resources.limits。Queue 的作用是从队列维度限制一组作业最多能使用多少资源。vGPU 资源的发现和容器内限制仍然依赖 volcano-vgpu-device-plugin、Volcano deviceshare 以及 HAMi-core。
九、几个容易踩坑的地方
1. 普通 HAMi 和 Volcano vGPU 不要混着理解
普通 HAMi 使用:
nvidia.com/gpu
nvidia.com/gpumem
nvidia.com/gpucores
Volcano vGPU 使用:
volcano.sh/vgpu-number
volcano.sh/vgpu-memory
volcano.sh/vgpu-cores
这两套资源名不是一回事。
如果使用 Volcano vGPU,就按 Volcano vGPU 的方式来,不需要额外安装普通 HAMi。
2. 不要同时混用多个 GPU device plugin
同一个 GPU 节点上同时部署 NVIDIA 官方 device plugin、HAMi device plugin、Volcano vGPU device plugin,容易出现资源注册和调度混乱。
建议一个节点上只选择一种 GPU 管理方式。
本文选择的是 Volcano vGPU device plugin。
3. Gang Scheduling 失败不一定是错误
如果 PodGroup 显示:
Reason: NotEnoughResources
Phase: Inqueue
并且 message 里有:
pod group is not ready
2 Pending, 2 minAvailable
这通常说明 Volcano 正在执行 Gang Scheduling 语义。
资源不够时,它不会只启动一部分 Pod,而是让整个 PodGroup 等待资源满足。
4. Queue 限制的是队列资源上限
Queue 的 capability 是队列级别的资源上限。它不是给某个 Pod 单独分配 GPU,也不是替代 resources.limits。
Pod 或 VolcanoJob 里仍然需要写:
resources:
limits:
volcano.sh/vgpu-number: 1
volcano.sh/vgpu-memory: 2000
volcano.sh/vgpu-cores: 30
Queue 只是从队列维度限制这类资源最多能用多少。
十、总结
这次测试主要验证了几个点。
第一,Volcano vGPU 路线和普通 HAMi 路线要分清楚。
普通 HAMi 使用 nvidia.com/* 资源名;Volcano vGPU 使用 volcano.sh/vgpu-* 资源名。本文使用的是 Volcano vGPU。
第二,Volcano vGPU 可以在单张 RTX 3070 Ti 上实现多个小 GPU 任务共享。
例如两个 Pod 分别申请:
volcano.sh/vgpu-memory: 2000
volcano.sh/vgpu-cores: 30
两个 Pod 可以同时 Running,并且容器内 nvidia-smi 能看到被限制后的显存。
第三,VolcanoJob 的 minAvailable 可以实现 Gang Scheduling。
当两个 worker 总资源满足时,PodGroup 进入 Running;当两个 worker 总资源超过单卡能力时,PodGroup 会保持 Inqueue 或 Pending,而不是只启动其中一部分 Pod。
第四,Queue 可以对 vGPU 资源做队列级别的限制。
通过 Queue 的 capability 可以限制某个队列最多使用多少 CPU、内存、vGPU number、vGPU memory 和 vGPU cores。
整体来看,HAMi + Volcano 联合使用时,可以这样理解:
volcano-vgpu-device-plugin / HAMi-core:解决 GPU 共享和容器内资源限制
Volcano Scheduler:解决批任务调度、Gang Scheduling、Queue 资源管理
对于 AI 训练、大模型推理、多租户 GPU 平台等场景,这两个能力组合起来,才能比较完整地覆盖“GPU 细粒度共享 + 批任务整体调度 + 队列资源管控”的需求。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)