Volcano队列
在共享异构算力资源(GPU/NPU) 集群中,算法开发、模型调优和生产训练等业务通常由不同团队共同使用同一批计算资源。如果所有训练任务都提交到同一个默认队列,容易出现以下问题:某个团队一次提交大量任务长期占用GPU/NPU,其他团队的任务无法及时运行;开发调试任务与生产训练任务相互竞争,关键训练缺少稳定的资源保障;某个队列空闲时,已分配给该队列的资源无法被其他队列利用,降低集群利用率。
通过Volcano队列(Queue),可以为不同团队或训练环境创建独立队列,并按CPU、内存、GPU/NPU等资源维度配置预留资源、应得资源和使用上限。队列空闲时可借出资源,资源所有者需要时可通过reclaim回收,兼顾资源保障与集群利用率。
典型使用场景如下:
- 多团队共享训练集群:按部门、租户或项目划分队列,避免单个团队无上限地消耗集群资源。
- 开发与生产训练分级:为生产队列配置更高的队列优先级或更多应得资源,使关键任务更容易获得资源。
- 异构资源弹性共享:允许繁忙队列借用其他队列的空闲资源,并在资源所有者需要时回收借出的资源。
- 多维异构资源配额:分别配置CPU、内存、nvidia.com/gpu或集群实际注册的其他扩展资源。
- 分层组织管理:启用分层队列后,可按业务层级组织队列结构,例如“部门 > 项目 > 环境”组织队列,并在父子队列之间继承和约束资源。
基本概念
| 概念 | 定义 | 作用 |
|---|---|---|
| Volcano Queue | 集群级资源(scheduling.volcano.sh/v1beta1),用于聚合PodGroup。不属于任何 Namespace,不提供租户隔离。 常见状态包括 :
|
|
| Volcano Job(vcjob) | Volcano提供的批处理任务类型(batch.volcano.sh/v1alpha1),相比原生Job支持队列调度、Gang调度、多Task、生命周期策略及训练框架插件。 |
|
| PodGroup | Volcano 为训练任务自动创建的调度单元(scheduling.volcano.sh/v1beta1),描述一组需协同调度的 Pod。minAvailable表示任务启动时至少需要同时可用的 Pod 数量。 | 通过 minAvailable定义任务启动所需的最小 Pod 数量;Queue 状态中的任务计数以 PodGroup 为维度,而非 Job 或 Pod。 |
| 队列资源模型(capacity插件) | 通过三级字段管理资源:
同一资源需满足guarantee.resource ≤ deserved ≤ capability。 | 实现资源的严格保障、灵活借用与总量封顶,支撑队列间的资源隔离与共享。 例如,某训练队列配置guarantee=2 GPU、deserved=6 GPU、capability=8 GPU,表示至少2个GPU只为该队列预留,应得6个GPU,即使集群仍有空闲资源,该队列最多使用8个GPU。 |
| 默认队列root | 系统内置根队列,是所有队列的顶层父队列。 | 用于集群级资源调度与分层队列管理,不可修改和删除。 |
| 默认队列default | 系统内置业务队列,父队列为root。 | 当Volcano Job未显式指定spec.queue时,任务默认落入此队列;不可修改和删除。 |
原理描述
训练任务提交到指定Queue后的主要处理流程如下。

流程说明如下:
- 用户创建Volcano任务,并通过spec.queue指定训练任务所属队列。
- Volcano准入组件校验队列是否存在、状态是否为Open。启用分层队列时,还会校验目标是否为叶子队列。任务只能提交到叶子队列,不能提交到非叶子队列。
- Volcano Controller根据任务生成PodGroup和训练Pod。PodGroup携带队列、最小可用成员数和优先级等调度信息。
- Scheduler执行enqueue动作,判断训练任务是否满足进入队列的条件。
- Scheduler执行allocate动作,并由capacity或proportion插件(表1)根据队列资源配置判断本次分配是否超过队列上限。
当其他队列存在空闲资源时,当前队列可以在不超过capability的前提下借用资源,提高集群利用率。当某队列需要取回其应得资源且集群资源不足时,reclaim动作从使用量超过deserved的其他队列中选择Pod进行回收,队列优先级、任务优先级和Gang约束会共同影响候选对象。分布式训练Pod被回收后,可能导致整个训练任务重启,因此应配置任务生命周期策略,并确保训练程序定期保存检查点。
| 插件 | 配额表达方式 | 适用场景 | 注意事项 |
|---|---|---|---|
| capacity | 直接配置各资源维度的deserved、capability和guarantee | GPU/NPU型号多、租户配额明确、需要精确多维配额 | 集群扩缩容后需要根据实际总资源调整绝对配额 |
| proportion | 根据Queue的weight占总权重的比例动态计算应得资源 | 集群规模经常变化、只需按比例公平共享 | 不使用deserved直接配置应得资源 |
capacity和proportion不能同时启用。对于需要明确控制GPU/NPU数量的训练场景,建议使用capacity。
前提条件
- 已创建CCE Standard或CCE Turbo集群,并已已安装可用的Volcano组件,包括Controller、Scheduler和Admission组件。
- 已安装目标GPU/NPU驱动及设备插件,节点能够上报训练任务所需的GPU/NPU扩展资源。
- 已安装并配置kubectl,且可以访问目标集群。
- 当前用户具有查看Scheduler ConfigMap、创建Queue以及在目标命名空间创建Volcano Job、ConfigMap和Pod的权限。
- 使用GPU或NPU时,已安装对应驱动和设备插件,节点能够上报相关扩展资源。
- 集群节点可以拉取示例使用的容器镜像。私网集群请将镜像同步到SWR,并替换示例中的镜像地址。
- 执行以下命令,确认Volcano相关API已注册。
kubectl api-resources | grep -E 'volcano|Queue|PodGroup'
预期可以查询到jobs.batch.volcano.sh、queues.scheduling.volcano.sh和 podgroups.scheduling.volcano.sh等资源。
- 执行以下命令,确认集群存在可分配的资源。
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.allocatable.nvidia\.com/gpu}{"\n"}{end}'如果输出为空,请先检查GPU驱动、设备插件和节点资源上报状态。本文以GPU资源为例,NPU资源请将JSONPath中的资源名称替换为集群实际注册的NPU资源名称。
约束与限制
- Queue是集群级资源,创建、修改和删除Queue通常需要集群管理员权限。
- Volcano原生Queue提供资源配额隔离,不直接提供用户身份隔离。CCE控制台可以通过Queue与IAM用户/用户组关联限制控制台上的任务提交权限,但用户仍可能通过kubectl等其他方式向关联之外的Queue提交任务。如需严格限制提交权限,应额外配置Kubernetes RBAC规则。
- 训练任务引用的Queue必须已经存在且状态为Open,否则任务创建会被拒绝。
- 启用分层队列后,训练任务只能提交到叶子队列,不能提交到root队列或父队列。
- capacity和proportion插件不能同时启用。本文使用capacity插件按具体资源数量管理Queue。
- 各资源维度应满足guarantee.resource <= deserved <= capability。分层队列中,子队列还受父队列相应资源上限约束。
- capability限制的是调度资源用量,不代表节点物理隔离。需要将训练任务固定到特定GPU/NPU节点池时,应结合节点亲和性、污点和容忍、NodeGroup等能力。
- 队列配额依赖Pod的资源请求。训练容器应准确配置 resources.requests;建议同时配置相同的limits,避免资源统计与实际消耗偏差过大。
- 使用capacity插件时,deserved和capability是明确的资源数量。集群扩缩容后,应检查Queue配置是否仍符合新的集群资源规模。
- 本文示例使用CPU和内存演示配额隔离,不依赖GPU/NPU节点。GPU/NPU资源的验证方法相同,只需在Queue和任务中使用集群实际注册的扩展资源名称。
创建Volcano队列
您可以通过以下方式创建Volcano队列,推荐根据实际场景选择合适的方式。
适用于快速创建标准队列,无需编写YAML场景。
- 登录CCE控制台。
- 在左侧导航栏中选择“AI容器”,单击“训练任务”页签。
- 在“训练任务”页签,选择目标集群,单击“Volcano队列”,然后单击“创建Volcano队列”。
- 在“创建Volcano队列”面板中配置以下信息。
当前页面不支持配置GPU和NPU虚拟化资源。如需设置虚拟化资源配额,需通过YAML文件配置。
表2 基本信息 参数
描述
“队列名称”
队列的唯一标识符,训练任务通过该名称指定目标Queue。
“父队列”
Queue所属的父Queue,用于建立分层Queue。训练任务应提交到叶子Queue。
表3 配额信息 参数
描述
“CPU配额”
- 资源上限:队列可使用的最大CPU核数。
- 应得量:队列在资源充足时可公平分配的CPU核数。
- 预留量:队列始终保留的CPU核数。
“内存配额”
- 资源上限:队列可使用的最大内存(MiB)。
- 应得量:队列在资源充足时可公平分配的内存。
- 预留量:队列始终保留的内存。
“GPU配额”
- 资源上限:队列可使用的最大GPU卡数。
- 应得量:队列在资源充足时可公平分配的GPU卡数。
- 预留量:队列始终保留的GPU卡数。
“昇腾Snt3配额”
- 资源上限:队列可使用的最大NPU卡数。
- 应得量:队列在资源充足时可公平分配的NPU卡数。
- 预留量:队列始终保留的NPU卡数。
“昇腾Snt9配额”
- 配置完成后,单击“确定”。
该方式适用于配置控制台表单未支持的Queue字段,以及GPU/NPU等异构虚拟化资源。
- 登录CCE控制台。
- 在左侧导航栏中选择“AI容器”,单击“训练任务”页签。
- 在“训练任务”页签,选择目标集群,单击“Volcano队列”,然后单击“YAML创建”。
- 在“YAML创建”面板中,执行以下任一操作。
- 导入文件:单击“导入”,选择本地已编写好的Queue YAML文件。
- 在线编辑:直接在编辑框中编写或粘贴YAML内容。
具体YAML文件示例和参数说明请参见示例:验证Volcano队列的资源隔离。
- 单击“确定”。
通过控制台为队列绑定用户/用户组
为队列关联用户/用户组后,被关联的用户/用户组将获得该Queue的查看权限(get/list),可在控制台中查看该队列的详细信息和状态。
示例:验证Volcano队列的资源隔离
本示例创建两个Queue(queue-team-a和queue-team-b),并提交三个最小化的Volcano任务,验证以下行为:
- Queue分别统计和限制资源用量。
- CPU、内存和GPU请求均未超过Queue剩余配额的任务可以正常运行。
- GPU请求超过Queue剩余配额的任务保持Pending。
- 一个Queue(queue-team-b)的剩余GPU配额不能用于突破另一个Queue(queue-team-a)的GPU资源上限。
示例不依赖训练框架,容器仅执行sleep命令,不执行实际GPU计算,验证重点集中在Queue配额和主调度流程上。所有任务均通过nvidia.com/gpu请求GPU资源。
资源规划
执行示例前,请确保集群满足以下资源要求:
- 至少有6核可分配CPU、12 GiB可分配内存和3个可分配GPU。
- 为系统组件预留额外资源。
- 两个配额内任务运行后,至少有一个GPU节点可以提供至少1核CPU、2 GiB内存和1个GPU,且没有其他业务占用该资源,以排除节点资源不足对验证结果的干扰。
- 其他Queue未在CPU、内存和GPU维度配置会影响本示例实际可用上限的预留资源。
| Queue | Deserved | Capability | 初始任务请求 | 初始任务运行后的剩余配额 |
|---|---|---|---|---|
| queue-team-a | 2 CPU、4 GiB、1 GPU | 2 CPU、4 GiB、1 GPU | 1 CPU、2 GiB、1 GPU | 1 CPU、2 GiB、0 GPU |
| queue-team-b | 4 CPU、8 GiB、2 GPU | 4 CPU、8 GiB、2 GPU | 2 CPU、4 GiB、1 GPU | 2 CPU、4 GiB、1 GPU |
步骤一:检查并配置Scheduler
- 执行以下命令,查看当前Scheduler配置。
kubectl get configmap volcano-scheduler-configmap -n volcano-system \ -o jsonpath='{.data.volcano-scheduler\.conf}'确认配置满足以下要求:
- actions:包含enqueue和allocate。
- 插件列表:包含capacity,不包含proportion(二者不可同时启用)。
- (可选)若当前配置不符合上述要求,修改前建议先备份当前配置,然后执行以下命令进行编辑。
kubectl edit configmap volcano-scheduler-configmap -n volcano-system
参考配置如下。请保留集群中其他业务需要的已有插件,不要直接覆盖整个ConfigMap。
data: volcano-scheduler.conf: | actions: "enqueue, allocate, backfill" tiers: - plugins: - name: priority - name: gang enablePreemptable: false - name: conformance - plugins: - name: drf enablePreemptable: false - name: predicates - name: capacity - name: nodeorder - name: binpack关键配置说明如下表所示。
配置项
类型
是否必选
描述
enqueue
调度动作
是
检查任务最小运行资源是否满足Queue剩余配额。通过检查后,PodGroup由Pending变为Inqueue。
allocate
调度动作
是
在Queue资源上限内为任务选择满足条件的节点并分配资源。
backfill
调度动作
否
尝试利用调度周期中的剩余节点资源。
capacity
插件
是
根据Queue的资源配置进行准入和分配检查。
proportion
插件
否
按Queue权重计算资源份额,与capacity不能同时启用。
gang
插件
否
按PodGroup的minAvailable检查任务最小运行条件。
- 配置修改完成后,执行以下命令重启Volcano Scheduler,使配置生效。
kubectl rollout restart deployment volcano-scheduler -n volcano-system kubectl rollout status deployment volcano-scheduler -n volcano-system
步骤二:创建两个Queue
- 创建名为queue-isolation-demo.yaml的文件(文件名可自定义),内容如下:
apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: queue-team-a spec: deserved: cpu: "2" memory: 4Gi nvidia.com/gpu: "1" capability: cpu: "2" memory: 4Gi nvidia.com/gpu: "1" --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: queue-team-b spec: deserved: cpu: "4" memory: 8Gi nvidia.com/gpu: "2" capability: cpu: "4" memory: 8Gi nvidia.com/gpu: "2"关键参数说明如下表所示。
参数
类型
描述
metadata.name
String
Queue名称,在集群内唯一,最长253个字符,并应符合DNS子域名格式。
spec.deserved
ResourceList
Queue的应得资源。本文将其设置为与capability相同,使示例只关注固定配额边界。
spec.capability
ResourceList
Queue可使用资源的硬上限。Queue中所有已分配及已进入Queue的任务不能突破该值。
spec.guarantee.resource
ResourceList
可选。仅供当前Queue使用的预留资源,配置时应小于或等于deserved。本文最小示例不配置该字段。
spec.parent
String
可选。父Queue名称;未指定时由系统关联到root。训练任务只能提交到叶子Queue。
nvidia.com/gpu
Integer
NVIDIA GPU扩展资源名称,取值为非负整数。本示例使用该资源名称设置Queue的GPU配额;如果集群注册了其他GPU资源名称,请同步替换Queue和任务中的资源名称。
- 创建Queue。
kubectl apply -f queue-isolation-demo.yaml
若回显类似如下,表示队列创建成功。
queue.scheduling.volcano.sh/queue-team-a created queue.scheduling.volcano.sh/queue-team-b created
- 查看Queue状态。
kubectl get queue queue-team-a queue-team-b \ -o custom-columns='NAME:.metadata.name,STATE:.status.state,PARENT:.spec.parent'
确认两个队列的status.state均为Open。
步骤三:提交配额内任务
- 创建命名空间。
kubectl create namespace queue-demo
- 创建名为jobs-within-quota.yaml的文件,内容如下。
apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: team-a-within-quota namespace: queue-demo spec: queue: queue-team-a schedulerName: volcano minAvailable: 1 tasks: - name: worker replicas: 1 template: spec: restartPolicy: Never containers: - name: worker image: busybox:1.36.1 command: ["sh", "-c", "sleep 3600"] resources: requests: cpu: "1" memory: 2Gi nvidia.com/gpu: "1" limits: cpu: "1" memory: 2Gi nvidia.com/gpu: "1" --- apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: team-b-within-quota namespace: queue-demo spec: queue: queue-team-b schedulerName: volcano minAvailable: 1 tasks: - name: worker replicas: 1 template: spec: restartPolicy: Never containers: - name: worker image: busybox:1.36.1 command: ["sh", "-c", "sleep 3600"] resources: requests: cpu: "2" memory: 4Gi nvidia.com/gpu: "1" limits: cpu: "2" memory: 4Gi nvidia.com/gpu: "1"GPU扩展资源不能超配,因此示例将每个容器的GPU requests和limits设置为相同的整数。busybox容器不会执行GPU计算,但Pod仍会占用所请求的GPU资源。如果集群无法直接拉取busybox:1.36.1,请将镜像同步到SWR并替换image字段。
- 提交任务。
kubectl apply -f jobs-within-quota.yaml
- 查看任务状态。
kubectl get vcjob -n queue-demo -o wide kubectl get podgroup -n queue-demo -o wide kubectl get pod -n queue-demo -o wide
当集群节点资源满足要求时,预期结果如下:
- team-a-within-quota和team-b-within-quota的任务状态均变为Running。
- 对应PodGroup状态均变为Running。
- 两个Pod均处于Running状态。
- queue-team-a已分配1 CPU、2GiB和1 GPU,剩余1 CPU、2GiB和0 GPU配额。
- queue-team-b已分配2 CPU、4GiB和1 GPU,剩余2 CPU、4GiB和1 GPU配额。
- 查看Queue已分配资源。
kubectl get queue queue-team-a \ -o jsonpath='{.status.state}{"\n"}{.status.allocated}{"\n"}' kubectl get queue queue-team-b \ -o jsonpath='{.status.state}{"\n"}{.status.allocated}{"\n"}'Queue状态同步可能存在短暂延迟。如果数值尚未更新,请等待一个调度周期后再次查询。
步骤四:提交超过Queue剩余配额的任务
- 创建名为job-over-quota.yaml的文件。
apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: team-a-over-quota namespace: queue-demo spec: queue: queue-team-a schedulerName: volcano minAvailable: 1 tasks: - name: worker replicas: 1 template: spec: restartPolicy: Never containers: - name: worker image: busybox:1.36.1 command: ["sh", "-c", "sleep 3600"] resources: requests: cpu: "1" memory: 2Gi nvidia.com/gpu: "1" limits: cpu: "1" memory: 2Gi nvidia.com/gpu: "1"该任务请求1 CPU、2 GiB和1 GPU。其CPU和内存请求未超过queue-team-a剩余的1 CPU和2 GiB配额,但该Queue的GPU剩余配额为0,因此GPU请求超过Queue剩余配额。
- 提交任务。
kubectl apply -f job-over-quota.yaml
- 查看任务和PodGroup状态。
kubectl get vcjob team-a-over-quota -n queue-demo -o wide kubectl get podgroup team-a-over-quota -n queue-demo -o wide kubectl describe podgroup team-a-over-quota -n queue-demo
预期结果如下:
- team-a-over-quota保持Pending。
- 对应PodGroup保持Pending,不会变为Inqueue或Running。
- PodGroup事件中包含Queue资源配额不足以及nvidia.com/gpu不足等信息。
- 在启用了延迟创建Pod的主调度流程中,该任务通过Queue配额检查前不会创建业务Pod;不同版本或配置下也可能创建Pending Pod,但任务均不能获得超过Queue上限的资源。
- queue-team-b剩余的1 GPU配额不会被team-a-over-quota使用。
- 已运行的team-a-within-quota和team-b-within-quota不受影响。
至此,已验证两个Queue分别管理CPU、内存和GPU资源用量,并通过capability阻止任务突破所属Queue的GPU资源上限。
步骤六:清理示例资源
删除Queue前,请确保其中不存在处于Running或Inqueue状态的PodGroup,也不存在需要保留的其他业务任务。
- 删除示例任务。
kubectl delete vcjob team-a-over-quota team-a-within-quota team-b-within-quota -n queue-demo
- 确认相关PodGroup和Pod已删除。
kubectl get podgroup,pod -n queue-demo
- 删除示例Queue和命名空间。
kubectl delete queue queue-team-a queue-team-b kubectl delete namespace queue-demo
常见问题
创建训练任务时报错"unable to find job queue"
- 可能原因:目标Queue不存在,或Volcano Admission组件的Queue缓存尚未完成同步。
- 排查步骤:
- 执行以下命令,确认Queue是否存在。
kubectl get queue
- 检查任务中spec.queue的值是否与上述输出中的Queue名称完全一致。
- Queue刚创建时可能存在短暂延迟,请等待数秒后重试。
- 执行以下命令,确认Queue是否存在。
创建训练任务时报错"can only submit job to queue with state Open"?
- 可能原因:目标Queue未处于Open状态。
- 排查步骤:
- 查看Queue详细状态与事件。
kubectl get queue <queue-name> -o yaml kubectl get events --field-selector involvedObject.kind=Queue,involvedObject.name=<queue-name>
- 等待Queue状态恢复为Open后再提交任务。
请勿手动修改status.state字段以绕过Queue生命周期管理。
- 查看Queue详细状态与事件。
训练任务长时间处于Pending状态?
- 可能原因:通常由资源不足、调度策略冲突或节点异常导致。
- 排查步骤:
- 检查PodGroup状态,确认Pending原因。
kubectl describe podgroup -n <namespace> <podgroup-name>
- 查看Queue配置和当前已分配资源。
kubectl get queue <queue-name> -o yaml
确认任务请求资源是否超过Queue的capability,或已达当前allocated上限。
- 检查任务的最小运行资源与Queue剩余配额。如果已分配资源 + 已进入Queue的资源 + 任务最小运行资源超过Queue实际可用上限,任务会保持Pending。
- 检查Scheduler是否启用了enqueue、allocate和capacity,并确认未同时启用proportion。
- 如果Queue配额充足,继续检查节点可分配资源、污点、标签、节点亲和性和设备插件状态。
- 查看Scheduler日志,关注异常调度事件。
kubectl logs -n volcano-system <volcano-scheduler-pod>
- 检查PodGroup状态,确认Pending原因。
配置Queue时提示资源大小关系不合法?
- 可能原因:违反了capacity插件的资源约束公式。
- 排查步骤:逐资源维度检查并确保满足以下关系。
guarantee.resource <= deserved <= capability
同时检查资源名称与单位是否正确。例如,CPU使用4或000m,内存使用16 Gi,GPU使用nvidia.com/gpu: "1"。
Queue配额充足,但任务仍无法运行?
Queue配额检查只是调度流程的一部分。任务还必须满足以下条件:
- 集群存在足够的CPU、内存、GPU/NPU或其他扩展资源。
- Pod的节点选择、节点亲和性、污点和容忍条件能够匹配节点。
- PodGroup的minAvailable能够同时满足。
- 镜像能够被节点正常拉取。
若需排查具体原因,请执行以下命令查看详情。
kubectl describe podgroup -n <namespace> <podgroup-name> kubectl describe pod -n <namespace> <pod-name>
Queue配额未满,但新任务仍提示配额不足?
Queue的status.allocated主要展示已分配资源,Scheduler在enqueue阶段还会统计已经进入Queue、尚未完成分配的任务资源。因此,仅根据status.allocated计算的表面剩余量可能高于Scheduler实际可接收的剩余量。
请同时检查同一Queue下处于Inqueue和Pending状态的PodGroup:
kubectl get podgroup -A -o wide
GPU/NPU仍有空闲,但任务因Queue配额无法调度?
这是Queue资源上限生效的预期结果。capability限制的是当前Queue可以使用的最大资源量,不以整个集群是否仍有空闲资源为判断依据。
如果需要允许该Queue使用更多资源,应由管理员评估其他Queue配置和集群容量后调整capability,而不是修改任务使其绕过目标Queue。
相关文档
以下为Volcano开源社区文档,供您深入了解相关机制:
- Queue:介绍Queue字段、状态、默认队列和分层队列基础概念。
- Volcano Job:介绍Volcano Job的queue、minAvailable、priorityClassName和Task等字段。
- Actions:介绍enqueue、allocate等主调度动作。
- Tutorials:包含使用自定义Queue提交Volcano任务的基础示例。