Kueue 如何管理 DRA 模式下的 GPU 配额

环境准备分几段走:先创建 K8s 集群,再用 GPU Operator 把 GPU Driver / Container Runtime 准备好,最后装 Kueue 和 NVIDIA DRA Driver。

1.1 创建 Kubernetes 集群

集群使用 KubeClipper 创建。KubeClipper 1.6.0 默认支持 Kubernetes 1.36.1、containerd 2.2.4,和本文环境一致,详细步骤可以参考:KubeClipper 1.6.0 发布:kcctl 优化与 K8s 1.36 支持。

快速创建单节点集群的命令如下:

curl -sfL https://oss.kubeclipper.io/get-kubeclipper.sh | KC_REGION=cn bash -

kcctl deploy

kcctl create cluster --name demo --master <NODE_IP> --untaint-master

集群起来后确认版本:

$ kubectl get node -owide

NAME STATUS ROLES VERSION CONTAINER-RUNTIME

lixd-test-gpu Ready control-plane v1.36.1 containerd://2.2.4

1.2 GPU 环境准备(GPU Operator)

GPU Driver、NVIDIA Container Toolkit 等基础组件使用 GPU Operator 安装。完整说明可以参考之前这篇:GPU 环境搭建指南:使用 GPU Operator 加速 Kubernetes GPU 环境搭建。

本文后面会安装 NVIDIA DRA Driver,所以安装 GPU Operator 时需要关闭 DevicePlugin:

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia && helm repo update

helm upgrade --install --wait gpu-operator

-n gpu-operator --create-namespace

nvidia/gpu-operator

--version=v26.3.1

--set driver.enabled=true

--set devicePlugin.enabled=false

--set devicePlugin.enabled=false:关闭 DevicePlugin,避免与后续安装的 DRA Driver 冲突。

安装完成后,确认 GPU Operator 组件正常运行:

$ kubectl get pods -n gpu-operator

NAME READY STATUS

gpu-operator-7bcbd487f5-h8dsd 1/1 Running

nvidia-container-toolkit-daemonset-zbpbv 1/1 Running

nvidia-operator-validator-8l2r5 1/1 Running

再确认节点能看到 GPU:

$ kubectl get node lixd-test-gpu -o jsonpath='{.metadata.labels.nvidia.com/gpu.product}{"\n"}'

Tesla-T4

1.3 安装 Kueue

Kueue 使用 0.18.1,安装方式和前两篇一样:

helm install kueue oci://registry.k8s.io/kueue/charts/kueue

--version=0.18.1

--namespace kueue-system

--create-namespace

--wait --timeout 300s

如果测试环境访问 registry.k8s.io 不稳定,也可以用 GitHub Release 里的 chart 包:

helm install kueue

https://github.com/kubernetes-sigs/kueue/releases/download/v0.18.1/kueue-0.18.1.tgz

--namespace kueue-system

--create-namespace

--wait --timeout 300s

1.4 接入 NVIDIA DRA Driver

最后安装 NVIDIA DRA Driver 25.12.0:

helm upgrade --install nvidia-dra-driver-gpu

nvidia/nvidia-dra-driver-gpu

--version 25.12.0

-n nvidia-dra-driver-gpu

--set gpuResourcesEnabledOverride=true

--create-namespace

--wait --timeout 300s

安装完成后,先看 DRA Driver 组件:

$ kubectl get pods -n nvidia-dra-driver-gpu

NAME READY STATUS

nvidia-dra-driver-gpu-controller-76864c66cb-s8tch 1/1 Running

nvidia-dra-driver-gpu-kubelet-plugin-grkbg 2/2 Running

再看 DeviceClass:

$ kubectl get deviceclass

NAME AGE

compute-domain-daemon.nvidia.com 2m47s

compute-domain-default-channel.nvidia.com 2m47s

gpu.nvidia.com 2m47s

mig.nvidia.com 2m47s

vfio.gpu.nvidia.com 2m47s

整卡调度用的是 gpu.nvidia.com。对应的 ResourceSlice 里能看到节点上的 T4:

$ kubectl get resourceslice

NAME NODE DRIVER POOL

lixd-test-gpu-gpu.nvidia.com-p8cdq lixd-test-gpu gpu.nvidia.com lixd-test-gpu

后面的 Job 会直接引用 gpu.nvidia.com 这个 DeviceClass,实际可分配设备则来自这些 ResourceSlice。

  1. Demo:使用 Kueue 调度 DRA 模式下的 GPU
    2.1 修改 Kueue DRA 配置
    DRA 和 Kueue 使用的资源名称并不是同一个。ResourceClaimTemplate 里写的是 deviceClassName: gpu.nvidia.com,而 ClusterQueue 里扣配额用的是资源名,所以这里需要做一次映射:

apiVersion: config.kueue.x-k8s.io/v1beta2

kind: Configuration

integrations:

frameworks:

  • batch/job
    resources:
    deviceClassMappings:
  • name: nvidia.com/gpu
    deviceClassNames:

deviceClassMappings 将 DRA DeviceClass 映射为 Kueue 配额资源

修改 Kueue manager config 后,需要重启 kueue-controller-manager 让新配置生效。

2.2 创建队列

这次只用一个队列,GPU 配额只给 1 张 T4。这样后面再提交第二个 Job 时,Pending 状态会看得很清楚。

apiVersion: v1

kind: Namespace
metadata:
name: p3-dra-demo

apiVersion: kueue.x-k8s.io/v1beta2

kind: ResourceFlavor
metadata:
name: p3-t4
spec:
nodeLabels:
nvidia.com/gpu.product: Tesla-T4

apiVersion: kueue.x-k8s.io/v1beta2

kind: ClusterQueue

metadata:

name: p3-dra-cq

spec:

namespaceSelector: {}

resourceGroups:

  • coveredResources:
    • cpu
    • memory
    • nvidia.com/gpu
      flavors:
    • name: p3-t4
      resources:
      • name: cpu
        nominalQuota: "8"
      • name: memory
        nominalQuota: 16Gi
      • name: nvidia.com/gpu
        nominalQuota: 1

apiVersion: kueue.x-k8s.io/v1beta2

kind: LocalQueue

metadata:

name: p3-dra-queue

namespace: p3-dra-demo

spec:

clusterQueue: p3-dra-cq

注意这里的 coveredResources 里包含 nvidia.com/gpu。这是映射后的逻辑资源名,不是 Pod 里直接写的扩展资源。

2.3 用 ResourceClaimTemplate 申请整卡

使用 DRA 之后,Job 不再写 resources.limits.nvidia.com/gpu: 1,而是引用一个独立的 ResourceClaimTemplate。

这里 Kueue 做的事情很直接:读取 Workload 引用的 ResourceClaimTemplate,识别里面的 deviceClassName 和 count,再通过 deviceClassMappings 折算成 ClusterQueue 里的配额资源。

本文不展开 extended resource 路径,避免把两种 DRA 接入方式混在一起。

先创建 ResourceClaimTemplate:

apiVersion: resource.k8s.io/v1

kind: ResourceClaimTemplate

metadata:

name: single-gpu

namespace: p3-dra-demo

spec:

spec:

devices:

requests:

  • name: gpu

exactly:

deviceClassName: gpu.nvidia.com

allocationMode: ExactCount

count: 1

这里有两个细节容易混:

deviceClassName 是 gpu.nvidia.com,不是 nvidia.com/gpu

ExactCount + count: 1 表示申请 1 张整卡

再提交 Kueue 管理的 Job:

apiVersion: batch/v1

kind: Job

metadata:

name: kueue-dra-running-a

namespace: p3-dra-demo

labels:

kueue.x-k8s.io/queue-name: p3-dra-queue

spec:

parallelism: 1

completions: 1

suspend: true

template:

spec:

resourceClaims:

  • name: gpu-claim

resourceClaimTemplateName: single-gpu

restartPolicy: Never

containers:

  • name: cuda-test

image: nvcr.io/nvidia/cuda:12.6.0-base-ubuntu24.04

command: "bash", "-c", "nvidia-smi -L \&\& echo KUEUE_DRA_RUNNING_A \&\& sleep 3600"

resources:

claims:

  • name: gpu-claim

Job 被 Kueue 准入后,会从 Suspended 变成 Running:

$ kubectl get job,pod,workload -n p3-dra-demo

NAME STATUS COMPLETIONS

job.batch/kueue-dra-running-a Running 0/1

NAME READY STATUS

pod/kueue-dra-running-a-kj7nw 1/1 Running

NAME QUEUE RESERVED IN ADMITTED

workload.kueue.x-k8s.io/job-kueue-dra-running-a-c3b3c p3-dra-queue p3-dra-cq True

ResourceClaim 已经分配:

$ kubectl get resourceclaim -n p3-dra-demo

NAME STATE

kueue-dra-running-a-kj7nw-gpu-claim-c6j4j allocated,reserved

容器里能看到 T4:

$ kubectl logs -n p3-dra-demo -l job-name=kueue-dra-running-a

GPU 0: Tesla T4 (UUID: GPU-6d8fdeb7-6247-e04e-81a7-7b42dc45180c)

KUEUE_DRA_RUNNING_A

2.4 看 Kueue 是否真的扣了 GPU 配额

直接看 Workload 的准入结果:

status:

admission:

clusterQueue: p3-dra-cq

podSetAssignments:

  • count: 1

flavors:

nvidia.com/gpu: p3-t4

resourceUsage:

nvidia.com/gpu: "1"

这说明 deviceClassMappings 已经生效:用户写的是 ResourceClaimTemplate,Kueue 扣的是 nvidia.com/gpu 这个逻辑配额。

再看看 ClusterQueue,可以发现 GPU 配额已经被扣掉了:

status:

admittedWorkloads: 1

flavorsUsage:

  • name: p3-t4
    resources:
    • name: nvidia.com/gpu
      total: "1"
      2.5 第二个整卡 Job 会被 Kueue 卡住
      队列里只有 1 张 GPU 配额。如果再提交一个同样申请 single-gpu 的 Job:

kueue-dra-running-a:1 x gpu.nvidia.com

kueue-dra-pending-b:1 x gpu.nvidia.com

$ kubectl get job,workload -n p3-dra-demo

NAME STATUS

job.batch/kueue-dra-running-a Running

job.batch/kueue-dra-pending-b Suspended

NAME QUEUE RESERVED IN ADMITTED

workload.kueue.x-k8s.io/job-kueue-dra-running-a-c3b3c p3-dra-queue p3-dra-cq True

workload.kueue.x-k8s.io/job-kueue-dra-pending-b-494a3 p3-dra-queue

再看 Workload 状态,就能发现为什么第二个 Job 一直起不来:

status:

conditions:

  • reason: Pending
    message: 'couldn''t assign flavors to pod set main: insufficient unused quota
    for nvidia.com/gpu in flavor p3-t4, 1 more needed'
    resourceRequests:
  • name: main
    resources:
    nvidia.com/gpu: "1"
  1. 几个容易踩坑的点
    DeviceClass 和配额资源不是同一个东西
    ResourceClaimTemplate 里写的是:

deviceClassName: gpu.nvidia.com

ClusterQueue 里写的是:

coveredResources:

  • nvidia.com/gpu
    两者靠 Kueue 配置里的 deviceClassMappings 关联起来。少了这段映射,Workload 会被标成 Inadmissible,原因类似:

DeviceClass gpu.nvidia.com is not mapped in DRA configuration

ResourceClaimTemplate 要单独创建

这两个名字最容易看混:

single-gpu:前面单独创建的 ResourceClaimTemplate,定义"我要 1 张 gpu.nvidia.com 整卡"。

gpu-claim:Pod 里的本地 claim 名字,后面容器通过它来使用 GPU。

Pod 里这段不是重新定义一个模板,而是引用已经存在的 single-gpu 模板:

resourceClaims:

  • name: gpu-claim
    resourceClaimTemplateName: single-gpu
    容器里再通过同一个 gpu-claim 关联到这次申请到的设备:

resources:

claims:

  • name: gpu-claim
    所以完整关系是:ResourceClaimTemplate(single-gpu) -> Pod resourceClaims(gpu-claim) -> container resources.claims(gpu-claim)。

Kueue 准入不等于设备已经分配

这里要注意一点:Kueue 只是负责"准入",真正把 GPU 分配给 Pod 的还是 kube-scheduler 和 DRA Driver。

所以生产环境里建议同时关注 ResourceClaim 状态和 Pod 状态。如果希望 Workload 在 Pod 长时间起不来时释放 Kueue 配额,可以结合 waitForPodsReady 做保护。

  1. 小结
    到这里可以看到,Kueue 并没有直接参与 GPU 分配,而是站在 Job 准入这一层,通过 deviceClassMappings 把 DRA 的设备申请转换成队列里的配额资源。这样既保留了 DRA 的设备模型,也让 GPU 可以继续纳入 Kueue 的统一配额管理。

组件 负责什么

NVIDIA DRA Driver 把 GPU 作为 gpu.nvidia.com DeviceClass / ResourceSlice 发布出来

Kueue 通过 deviceClassMappings 把 DRA 设备折算成 nvidia.com/gpu 配额

kube-scheduler 在 Pod 调度阶段完成 ResourceClaim 的实际设备分配

相关推荐
DianSan_ERP10 小时前
电商架构演进:如何在高并发场景下实现多平台API的标准化履约?
运维·前端·网络·安全·架构·自动化
恒53910 小时前
Linux文件系统I
linux·运维·服务器
阿成学长_Cain10 小时前
Linux ipcs 命令超全详解:查看共享内存 / 消息队列 / 信号量,IPC 运维必备
linux·运维·服务器·网络·数据库
青瓦梦滋11 小时前
协议定制/序列化-反序列化(Linux视角)
linux·服务器·网络·c++
运维老郭13 小时前
【K8s运维实战】Kubernetes临时存储卷实战:emptyDir核心用法与gitRepo弃用迁移指南
运维·云原生·kubernetes
珠海西格电力13 小时前
云边端协同架构:零碳园区管理系统的技术底座
大数据·运维·人工智能·算法·架构·能源
阿成学长_Cain14 小时前
Linux dirs命令详解|Bash目录堆栈管理快速切换目录实战教程
linux·运维·前端·数据库
小羊Yveesss14 小时前
2026年微信小程序后端怎么搭建?后台、数据、接口和运维怎么选
运维·微信小程序·小程序