Volcano Capacity 插件 DeviceClass 配额(DRA Quota)设计解析与实战指南
2026/9/17 20:43:41 网站建设 项目流程

Volcano Capacity 插件 DeviceClass 配额(DRA Quota)设计解析与实战指南

【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano

本文围绕 Volcano 开源仓库中 DeviceClass Quota Support in Capacity Plugin 设计文档,深入讲解如何让 Kubernetes Dynamic Resource Allocation(DRA)资源接入 Volcano 已有的队列配额模型,并结合 用户指南 与 capacity 插件源码 给出完整的配置示例、启用步骤与底层实现原理。读完本文,你将掌握在 Volcano 队列上配置整卡(Device Count)配额、可消耗容量(Consumable Capacity)配额、混合资源配额以及共享 ResourceClaim 计费语义的完整实战方案。

背景:DRA 引入后,队列配额的问题依然存在

Volcano 的 capacity 插件已经为 CPU、内存以及其他标准资源提供了成熟的队列配额管理,核心语义由队列上的capabilitydeservedguarantee三个字段表达。Kubernetes DRA(Dynamic Resource Allocation)则带来了另一套资源模型,核心对象包括DeviceClassResourceClaimResourceSlice

对使用者而言,业务诉求并没有因为资源模型变化而改变:一个团队希望明确声明“这个队列最多可以使用多少 DRA 设备”“这个队列可以借用多少软上限”“这个队列保底获得多少资源份额”。因此设计目标非常明确——让 DRA 资源直接参与现有队列配额模型,而不是为 DRA 单独引入一套平行的配额 API。相关背景可参考 Capacity 插件设计 与 层次化队列设计。

设计目标与非目标

设计目标

  1. 复用现有队列字段capabilitydeservedguarantee
  2. 同时支持整设备配额(whole-device quota)与可消耗容量配额(consumable-capacity quota);
  3. 保持 DRA 配额语义与现有 capacity 插件行为一致;
  4. 同时支持直接引用ResourceClaim与引用ResourceClaimTemplate两种用法;
  5. 让共享ResourceClaim的计费方式对用户直观可理解。

非目标

  • 不管理物理设备的放置或分配细节;
  • 不替代 Kubernetes DRA 自身的调度逻辑;
  • 不定义新的 DRA 专用队列 CRD 结构。

核心思想:用保留 Key 格式在队列 ResourceList 中表达 DRA 配额

DRA 配额不新增字段,而是直接使用队列ResourceList中的保留 Key 格式来表达:

Key 格式示例含义
deviceclass/<DeviceClass>deviceclass/gpu.nvidia.com: "8"按设备数量限制
<dim>.deviceclass/<DeviceClass>cores.deviceclass/hami-core-gpu.project-hami.io: "800"按可消耗容量维度限制

这一设计使得 DRA 资源与cpumemory以及设备插件资源处于同一个配置模型之中,用户无需学习第二套配额模型。

源码印证:Key 的解析逻辑

在 capacity.go 中定义了三个关键常量:

DeviceClassCountPrefix = "deviceclass/" DeviceClassCapacitySep = ".deviceclass/"

parseDRAResourceList函数(capacity.go)对两种 Key 格式分别处理:

  • 若资源名包含.deviceclass/,则拆分为“维度名 + DeviceClass”,归入该 DeviceClass 的Capacity映射;
  • 若资源名以deviceclass/开头,则截取 DeviceClass 名,作为设备数量Count记录。

解析结果被封装为 DRAResource 结构体,其中Count表示设备总数,Capacity表示维度名到请求量的映射。测试 TestParseDRAResourceListCombinesCountAndCapacity 验证了 Count 与 Capacity 能被同时解析合并。

队列语义不变:capability / deserved / guarantee

对于 DRA 资源,队列字段的含义与普通资源完全一致:

字段含义
capability硬上限(hard upper bound)
deserved软份额,可在其周围借出或回收(soft share)
guarantee最低受保护份额(minimum protected share)

这意味着用户不需要为 DRA 学习第二套配额模型,直接复用既有的 capacity 插件语义即可。从源码看,newDRAQuotaAttr(capacity.go)直接从队列的capabilitydeservedguarantee三份 ResourceList 中解析出 DRA 配额属性draQuotaAttr,该结构分别维护每个 DeviceClass 的capabilitydeservedguaranteeallocated(当前分配)与inqueue(会话内已准入)状态。

配额配置实战

1. 整卡配额(Whole-Device Quota)

当队列需要按设备数量限制时,使用deviceclass/<name>格式:

apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: gpu-team spec: reclaimable: true capability: cpu: "64" memory: "256Gi" "deviceclass/gpu.nvidia.com": "8" deserved: "deviceclass/gpu.nvidia.com": "4" guarantee: "deviceclass/gpu.nvidia.com": "1"

含义:gpu-team队列最多同时使用 8 张gpu.nvidia.com设备,软份额为 4 张,保底 1 张。

2. 可消耗容量配额(Consumable-Capacity Quota)

当队列需要按 vGPU 核数、显存等可消耗维度限制时,使用<dim>.deviceclass/<name>格式:

apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: vgpu-team spec: reclaimable: true capability: "cores.deviceclass/hami-core-gpu.project-hami.io": "800" "memory.deviceclass/hami-core-gpu.project-hami.io": "320Gi" deserved: "cores.deviceclass/hami-core-gpu.project-hami.io": "400" guarantee: "cores.deviceclass/hami-core-gpu.project-hami.io": "100"

3. 混合资源队列(Mixed Resource Queues)

一个队列可以同时包含传统资源、设备插件资源、整卡 DRA 配额和 DRA 容量维度:

apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: ml-team spec: reclaimable: true capability: cpu: "100" memory: "200Gi" "nvidia.com/gpu": "4" "deviceclass/gpu.nvidia.com": "8" "cores.deviceclass/hami-core-gpu.project-hami.io": "800" "memory.deviceclass/hami-core-gpu.project-hami.io": "320Gi"

启用 capacity 插件与 DRA 配额

使用前需要满足以下前提:

  1. Kubernetes 集群已启用 DRA;
  2. 集群中已安装支持 DRA 的驱动;
  3. Volcano 已安装并启用了capacity插件。

编辑调度器配置:

kubectl edit cm -n volcano-system volcano-scheduler-configmap

确保capacity插件已启用;若需要队列共享与回收(reclaim)行为,还需要启用reclaimaction。示例:

kind: ConfigMap apiVersion: v1 metadata: name: volcano-scheduler-configmap namespace: volcano-system data: volcano-scheduler.conf: | actions: "enqueue, allocate, backfill, reclaim" tiers: - plugins: - name: priority - name: gang - name: conformance - plugins: - name: drf - name: predicates - name: capacity arguments: capacity.DynamicResourceAllocationEnable: true capacity.DRAConsumableCapacityEnable: true - name: nodeorder

两个插件参数均为可选。从 New 函数 可见,未设置时 Volcano 默认采用对应 Kubernetes feature gate 的值作为默认值:

  • capacity.DynamicResourceAllocationEnable:控制是否执行 DRA 配额检查,默认取 Kubernetes 的DynamicResourceAllocationfeature gate;
  • capacity.DRAConsumableCapacityEnable:控制是否检查 DRA 内部的容量维度,默认取 Kubernetes 的DRAConsumableCapacityfeature gate。

checkDRAAllocatable(capacity.go)中可以看到:设备数量检查使用饱和加法计算allocated + inqueue + request是否超过capability.Count;而容量维度检查仅在consumableCapacityEnabled为真时进行,若请求的维度未在 capability 中定义或累加后超过配额上限,则直接判定不可分配。

请求如何被解释:两种用户侧用法

从队列视角看,DRA 配额由ResourceClaim请求消耗,支持两种模式:

  • Pod 直接引用一个ResourceClaim
  • Pod 引用ResourceClaimTemplate,由 Kubernetes 为 Pod 创建实际的 claim。

两种情况下队列配额视图一致:Volcano 将请求计入对应的DeviceClass

方式一:使用 ResourceClaimTemplate(推荐,每个 Pod 独立 claim)

apiVersion: resource.k8s.io/v1 kind: ResourceClaimTemplate metadata: name: gpu-template namespace: default spec: spec: devices: requests: - name: gpu-request exactly: deviceClassName: gpu.nvidia.com count: 2 allocationMode: ExactCount --- apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: gpu-job spec: schedulerName: volcano queue: gpu-team minAvailable: 1 tasks: - replicas: 1 name: worker template: spec: resourceClaims: - name: gpu resourceClaimTemplateName: gpu-template containers: - name: main image: nvidia/cuda:11.0-base command: ["nvidia-smi"] resources: requests: cpu: "2" memory: "4Gi" claims: - name: gpu

方式二:直接引用 ResourceClaim(适合多 Pod 共享同一 claim)

apiVersion: resource.k8s.io/v1 kind: ResourceClaim metadata: name: shared-gpu namespace: default spec: devices: requests: - name: gpu-request exactly: deviceClassName: gpu.nvidia.com count: 2 allocationMode: ExactCount shareable: true --- apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: shared-gpu-job spec: schedulerName: volcano queue: gpu-team minAvailable: 2 tasks: - replicas: 2 name: worker template: spec: resourceClaims: - name: gpu resourceClaimName: shared-gpu containers: - name: main image: nvidia/cuda:11.0-base command: ["nvidia-smi"] resources: requests: cpu: "2" memory: "4Gi" claims: - name: gpu

共享 ResourceClaim 语义:按 claim 计费一次

当多个 Pod 引用同一个可共享的ResourceClaim时,配额应按 claim 计数一次,而不是按 Pod 计数多次。这符合用户直觉:一个逻辑共享 claim 应只消耗一份队列配额,不能让队列用量因为多个 Pod 挂载同一共享 claim 而虚高。

源码印证:resourceClaimRefs 引用计数

在 capacity.go 的addTaskDRAAllocated中可以看到具体实现:每个队列维护resourceClaimRefs映射(claim 键到引用计数),只有当某个 claim 在该队列中的引用计数为 0(首次出现)时才真正累加 DRA 分配;随后递增引用计数。removeTaskDRAAllocated(capacity.go)在引用计数降为 1 时才扣减配额并删除记录,否则只做递减。

测试 TestSharedResourceClaimIsChargedOnce 明确验证了这一行为:两个任务共享同一个 claim 时,第二个任务不再额外消耗 DRA 配额;而两个不同的 claim 仍会分别计费,超限时会被拒绝。

与集群容量的关系:逻辑边界与物理分配的互补

队列配额是逻辑调度边界,物理设备可用性仍由 Kubernetes DRA 及其安装的驱动决定。两者职责互补而非重叠:

  • Volcano 检查队列是否被允许消耗更多某个DeviceClass的资源;
  • Kubernetes DRA 检查是否存在匹配的物理分配方案。

对于可消耗容量,Volcano 统计的是逻辑总量。例如一个请求 2 台设备、每台 8Gi 显存的申请,将消耗队列memory.deviceclass/<DeviceClass>配额中的 16Gi。但这不能解决物理碎片问题:即使集群有两台 8Gi 设备,一个需要在单台设备上 10Gi 的 Pod 仍可能通过队列配额检查,却在最终 DRA 分配阶段失败。测试 TestCheckDRAAllocatable_overflowRejected 也验证了设备数与 inqueue 累加溢出时会被拒绝的边界行为。

根队列与总资源视图

对于 DRA 资源,集群范围的总量既可以来自实际集群状态,也可以来自管理员显式的队列配置。核心的用户侧规则是:

  • 当管理员需要更强的逻辑边界,或自动汇总的总量不足以满足其环境需求时,可以显式配置根队列的 DRA 总量。

在层次化队列场景下,源码通过getDRADelta(capacity.go)计算叶子队列 DRA 分配增量,并仅对祖先队列 capability 中配置过的 DeviceClass 进行增量传播(见 buildHierarchicalQueueAttrs),保证祖先队列的 DRA 视图正确汇总。

不支持或延后的场景

第一版设计刻意保持窄范围,以下场景不是主要目标:

  • allocationMode: All
  • FirstAvailable风格的优先级请求;
  • 依赖更特殊设备语义的可分区设备总量统计。

这些场景在 Kubernetes DRA 中仍然存在,但不是本文所述的主要配额计费模型。用户指南(how_to_use_dra_quota.md)同样提醒:若环境重度依赖这些模式,在将其视为严格的队列配额信号前需仔细评估行为。

观察队列用量

可以通过以下命令查看队列的分配状态:

kubectl get queue -o yaml

DRA 用量出现在status.allocated中,例如:

status: allocated: "deviceclass/gpu.nvidia.com": "4" "cores.deviceclass/hami-core-gpu.project-hami.io": "400"

从源码看,AllocateFuncDeallocateFunc事件处理器(capacity.go)在任务分配/释放时同步维护attr.allocated与 DRA 分配计数,并更新队列指标,因此status.allocated反映的是实时配额占用。

队列共享示例

capabilitydeservedguarantee模型同样适用于 DRA 资源,可以让多个队列按普通 capacity 语义共享同一个 DRA 资源池:

apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: queue-a spec: reclaimable: true capability: "deviceclass/gpu.nvidia.com": "6" deserved: "deviceclass/gpu.nvidia.com": "3" guarantee: "deviceclass/gpu.nvidia.com": "1" --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: queue-b spec: reclaimable: true capability: "deviceclass/gpu.nvidia.com": "6" deserved: "deviceclass/gpu.nvidia.com": "5" guarantee: "deviceclass/gpu.nvidia.com": "2"

为什么这样设计

该设计的核心取舍是:保持 DRA 配额体验与既有 Volcano 队列管理融为一体,而不是另建一套仅针对 DRA 的配额系统。由此带来四个直接收益:

  • 不新增 DRA 专用队列 API 面;
  • 配额语义与现有 capacity 插件资源完全一致;
  • 硬上限、软共享、保底三种能力的工作流不变;
  • 一套配置模型同时覆盖 CPU、内存、设备插件与 DRA。

最佳实践

  1. 使用ResourceClaimTemplate管理每个 Pod 独立的分配生命周期;
  2. 仅在确实需要共享时才使用直接ResourceClaim
  3. 让队列capability与实际集群资源策略保持一致;
  4. 使用deservedguarantee表达团队共享规则,而不只是硬上限;
  5. 混合环境中,在同一个队列内同时配置 DRA Key 与普通资源 Key。

参考资料

  • DeviceClass Quota 设计文档
  • DeviceClass Quota 用户指南
  • Capacity 插件用户指南
  • Capacity 插件设计
  • Capacity 插件上的层次化队列
  • capacity 插件源码
  • capacity 插件测试用例
  • DRAResource 数据结构定义

【免费下载链接】volcanoA Cloud Native Batch System (Project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/vol/volcano

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询