在 Kubernetes 里用 GPU 这类设备,大家习惯走 DevicePlugin。但 AI workload 越来越复杂,DevicePlugin 的短板越来越明显——没法描述设备属性,调度器不参与分配,Pod 经常调度到节点后才发现资源不够 。
DRA(Dynamic Resource Allocation,动态资源分配)就是 Kubernetes 针对这些问题推出的新框架。
DRA 核心功能在 Kubernetes 1.34 已 GA ,可以放心用在生产环境。
1. DRA 解决什么问题?
DevicePlugin 的局限性
只能上报"数量",无法描述设备属性
调度器不参与分配,导致调度冲突
不支持资源预留
DRA 的核心改进
例如:
DevicePlugin :用户申请 1 个 GPU → 调度器随机选节点 → Kubelet 本地分配 -> Pod 启动后发现显存不够 OOM(比如你想要 A100 80GB,但被调度到了只有 V100 16GB 的节点,因为调度器无法区分 GPU 型号)
DRA :用户显式申请一个"显存>40Gi 的 GPU" → 调度器精确匹配 → 预分配成功 → Pod 正常启动
2. 部署环境
2.1 前置条件
K8s 相关:
Container Runtime 相关
CDI must be enabled in the underlying container runtime (such as containerd or CRI-O). ps:K8s 最好 1.34+,Containerd 则是 v1.7.x 及以上。
v1.32+ 已内置(beta),v1.34 GA
2.2 GPU Operator 安装
NVIDIA 官方在推进将 DRA 也集成到 GPU Operator,不过目前还没有完成,需要分别安装。
安装 GPU Operator 时需要指定不安装 DevicePlugin ,否则会和后续安装的 DRA GPU Plugin 冲突。
安装命令如下:
1
2
3
4
5
6
7
8
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
核心参数
1
2
# 关闭 DevicePlugin
--set devicePlugin.enabled= false
2.3 DRA 安装
NVIDIA 提供的 DRA Driver:dra-driver-nvidia-gpu ,包含了下面两个 plugin:
GPU Plugin :用于替代之前的 DevicePlugin,即:https://github.com/nvidia/k8s-device-plugin
ComputeDomain Plugin :此插件专门用于支持 Multi-Node NVLink (MNNVL) ,这是 NVIDIA GB200 NVL72 等新一代系统实现节点间 GPU 高速直连的关键技术。它引入 ComputeDomain 这一抽象概念,用于在多个 Pod(可能跨节点)之间自动建立并保障一个安全、隔离的 NVLink 通信域。
大部分主流的 GPU 都是用不上这个功能的,默认关闭即可 安装命令如下:
1
2
3
4
5
6
7
helm upgrade --install nvidia-dra-driver-gpu nvidia/nvidia-dra-driver-gpu \
--version= "25.12.0" \
--create-namespace \
--namespace nvidia-dra-driver-gpu \
--set resources.gpus.enabled= true \
--set resources.computeDomains.enabled= false \
--set nvidiaDriverRoot = /run/nvidia/driver
注意:在 KEP 5004 正式发布之前,resources.gpus.enabled=true的 DRA 驱动无法与标准的 NVIDIA GPU DevicePlugin 同时安装 。两者会因管理相同的扩展资源(nvidia.com/gpu)而发生冲突。
可以通过 --set 'gpuResourcesEnabledOverride=true' 安装。
核心参数:
1
2
3
4
5
6
# 开启 GPU 插件,关闭 computeDomains 插件
--set resources.gpus.enabled= true \
--set resources.computeDomains.enabled= false \
# 对于使用 GPU Operator 安装的驱动,需要通过 nvidiaDriverRoot 参数指定下目录
# /run/nvidia/driver 正好是 GPU Operator 安装的位置
--set nvidiaDriverRoot = /run/nvidia/driver
2.4 验证
查看 ResourceSlice
对于 DevicePlugin 来说是通过直接在 node 的 capacity 字段上展示nvidia.com/gpu 来表示该节点上有多少张 GPU。
1
2
3
4
5
6
7
8
9
root@GB200-POD2-F06-Node05:~# kubectl get node gb200-pod2-f06-node05 -oyaml| grep "capacity:" -A 7
capacity:
cpu: "144"
ephemeral-storage: 1840577300Ki
hugepages-2Mi: "0"
hugepages-16Gi: "0"
hugepages-512Mi: "0"
memory: 1002716864Ki
nvidia.com/gpu: "4"
比如上面这个节点 capacity 信息,只能看出该节点有 4 张 GPU,但是其他的:型号、显存、拓扑等信息完全无法得知。
DRA 则是有单独的 ResourceSlice 对象记录详细信息
暂时忽略这里面的 compute-domain 资源
1
2
3
4
5
6
root@GB200-POD2-F06-Node05:~# kubectl get ResourceSlice
NAME NODE DRIVER POOL AGE
gb200-pod2-f06-node05-compute-domain.nvidia.com-ftn4j gb200-pod2-f06-node05 compute-domain.nvidia.com gb200-pod2-f06-node05 18s
gb200-pod2-f06-node05-gpu.nvidia.com-j7ggv gb200-pod2-f06-node05 gpu.nvidia.com gb200-pod2-f06-node05 18s
gb200-pod2-f06-node06-compute-domain.nvidia.com-bjwf4 gb200-pod2-f06-node06 compute-domain.nvidia.com gb200-pod2-f06-node06 18s
gb200-pod2-f06-node06-gpu.nvidia.com-bbv4b gb200-pod2-f06-node06 gpu.nvidia.com gb200-pod2-f06-node06 18s
以 gb200-pod2-f06-node05-gpu.nvidia.com-j7ggv 为例,查看详情:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
root@GB200-POD2-F06-Node05:~/lixd/dra/demo# kubectl get ResourceSlice gb200-pod2-f06-node05-gpu.nvidia.com-j7ggv -oyaml
apiVersion : resource.k8s.io/v1
kind : ResourceSlice
metadata :
name : gb200-pod2-f06-node05-gpu.nvidia.com-j7ggv
ownerReferences :
- apiVersion : v1
controller : true
kind : Node
name : gb200-pod2-f06-node05
spec :
devices :
- attributes :
addressingMode :
string : ATS
architecture :
string : Blackwell
brand :
string : Nvidia
cudaComputeCapability :
version : 10.0.0
driverVersion :
version : 580.126.20
productName :
string : NVIDIA GB200
type :
string : gpu
uuid :
string : GPU-137d7996-cb8e-7683-e47d-9c99e6f49eb5
capacity :
memory :
value : 189471Mi
name : gpu-0
# ... 省略 gpu-1, gpu-2, gpu-3 的类似内容
driver : gpu.nvidia.com
nodeName : gb200-pod2-f06-node05
pool :
name : gb200-pod2-f06-node05
里面记录了节点上所有 GPU 的详细信息,关键属性包括:
type: string: gpu(设备类型)
architecture: string: Blackwell(GPU架构)
brand: string: Nvidia(品牌)
productName: string: NVIDIA GB200(产品名)
cudaComputeCapability: version: 10.0.0(计算能力)
driverVersion: version: 580.126.20(驱动版本)
resource.kubernetes.io/pciBusID(PCI总线地址)
容量 (capacity):目前只显示了 memory: 189471Mi。
查看 DeviceClass
在 ResourceSlice展示了资源的‘库存清单’后,DeviceClass则定义了如何使用这些资源的‘筛选规则’。
1
2
3
4
5
6
7
root@GB200-POD2-F06-Node05:~# kubectl get deviceclass
NAME AGE
compute-domain-daemon.nvidia.com 122m
compute-domain-default-channel.nvidia.com 122m
gpu.nvidia.com 122m
mig.nvidia.com 122m
vfio.gpu.nvidia.com 122m
例如 gpu.nvidia.com deviceclass 内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@GB200-POD2-F06-Node05:~# kubectl get DeviceClass gpu.nvidia.com -oyaml
apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
annotations:
meta.helm.sh/release-name: nvidia-dra-driver-gpu
meta.helm.sh/release-namespace: nvidia-dra-driver-gpu
creationTimestamp: "2026-04-18T11:10:48Z"
generation: 1
labels:
app.kubernetes.io/managed-by: Helm
name: gpu.nvidia.com
resourceVersion: "51521963"
uid: c5143f4a-0dec-4eae-9bbc-a00c4d806159
spec:
selectors:
- cel:
expression: device.driver == 'gpu.nvidia.com' && device.attributes[ 'gpu.nvidia.com' ] .type
== 'gpu'
DeviceClass 中通过 CEL 定义规则
1
2
3
cel:
expression: device.driver == 'gpu.nvidia.com' && device.attributes[ 'gpu.nvidia.com' ] .type
== 'gpu'
含义如下:
设备的驱动必须是 gpu.nvidia.com 设备的类型必须是 gpu 满足这两个条件的设备就属于这个 DeviceClass。
3. 运行第一个 DRA GPU Pod
3.1 ResourceClaimTemplate
创建 ResourceClaimTemplate 申请一个 GPU
1
2
3
4
5
6
7
8
9
10
11
12
13
14
apiVersion : resource.k8s.io/v1
kind : ResourceClaimTemplate
metadata :
name : single-gpu
namespace : default
spec :
spec :
devices :
requests :
- name : gpu
exactly :
deviceClassName : gpu.nvidia.com # 匹配前面的 DeviceClass
allocationMode : ExactCount
count : 1 # 数量
3.2 Pod 申请 resourceClaim
然后创建 Pod 指定使用这个 resourceClaimTemplate,通过 resourceClaimTemplateName 指定名称进行关联。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# gpu-test-pod.yaml
apiVersion : v1
kind : Pod
metadata :
name : gpu-test-pod
namespace : default
spec :
containers :
- name : cuda-container
image : nvidia/cuda:12.1.0-base-ubuntu22.04
command : [ "bash" , "-c" ]
args : [ "nvidia-smi -L && echo 'GPU allocation successful.' && sleep 3600" ]
# 在容器中引用Pod级别声明的资源
resources :
claims :
- name : gpu-claim
# 声明Pod需要资源,并指定使用哪个模板
resourceClaims :
- name : gpu-claim
resourceClaimTemplateName : single-gpu
3.3 验证
验证调度结果
1
2
3
4
5
6
7
8
9
10
11
12
# 查看Pod状态和调度节点
kubectl get pod gpu-test-pod -o wide
# 查看Pod的详细事件,确认资源分配过程
kubectl describe pod gpu-test-pod
# 查看自动生成的ResourceClaim及其状态
kubectl get resourceclaim
kubectl describe resourceclaim <自动生成的claim名称>
# 查看Pod日志,确认GPU信息被正确识别
kubectl logs gpu-test-pod
Pod 状态和调度节点
1
2
3
root@GB200-POD2-F06-Node05:~/lixd/dra/demo# kubectl get pod gpu-test-pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
gpu-test-pod 1/1 Running 0 95s 172.25.114.35 gb200-pod2-f06-node05 <none> <none>
Pod 成功启动,并被调度器精确地分配到了拥有符合条件 GPU 的 gb200-pod2-f06-node05 节点。
resourceclaim 详情
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
root@GB200-POD2-F06-Node05:~/lixd/dra/demo# kubectl get resourceclaim
NAME STATE AGE
gpu-test-pod-gpu-claim-7rqsj allocated,reserved 37s
root@GB200-POD2-F06-Node05:~/lixd/dra/demo# kubectl describe resourceclaim gpu-test-pod-gpu-claim-7rqsj
Name: gpu-test-pod-gpu-claim-7rqsj
Namespace: default
Labels: <none>
Annotations: resource.kubernetes.io/pod-claim-name: gpu-claim
API Version: resource.k8s.io/v1
Kind: ResourceClaim
Metadata:
Creation Timestamp: 2026-04-19T06:26:52Z
Finalizers:
resource.kubernetes.io/delete-protection
Generate Name: gpu-test-pod-gpu-claim-
Owner References:
API Version: v1
Block Owner Deletion: true
Controller: true
Kind: Pod
Name: gpu-test-pod
UID: f92cb808-a813-419c-b111-7d9e4e402f59
Resource Version: 51788271
UID: 86e7f3f0-052b-4a61-8e4f-36e2020dd2fc
Spec:
Devices:
Requests:
Exactly:
Allocation Mode: ExactCount
Count: 1
Device Class Name: gpu.nvidia.com
Name: gpu
Status:
Allocation:
Devices:
Results:
Device: gpu-0
Driver: gpu.nvidia.com
Pool: gb200-pod2-f06-node05
Request: gpu
Node Selector:
Node Selector Terms:
Match Fields:
Key: metadata.name
Operator: In
Values:
gb200-pod2-f06-node05
Reserved For:
Name: gpu-test-pod
Resource: pods
UID: f92cb808-a813-419c-b111-7d9e4e402f59
Events: <none>
查看 Pod 日志
查看 Pod 日志,成功分配了一个 GPU:
1
2
3
root@GB200-POD2-F06-Node05:~/lixd/dra/demo# kubectl logs gpu-test-pod
GPU 0: NVIDIA GB200 ( UUID: GPU-137d7996-cb8e-7683-e47d-9c99e6f49eb5)
GPU allocation successful.
4. 小结
这篇文章带大家从零搭了一套 DRA 环境,跑通了第一个 GPU Pod。几个关键点:
ResourceSlice 是设备的"库存表",把 GPU 型号、显存、驱动版本都暴露给调度器 DeviceClass 用 CEL 表达式定义筛选规则,决定哪些设备归哪一类 ResourceClaim / ResourceClaimTemplate 是用户侧的"申购单",Pod 通过它拿到具体设备 和 DevicePlugin 最大的区别:调度器在做调度决策时就能看到设备的全部信息,不再盲选,可以做更精细的调度。
DRA(Dynamic Resource Allocation) 的引入,标志着 Kubernetes 在 资源管理 方向的重大演进。它不仅解决了现有资源管理模型的痛点,还为复杂的异构硬件管理提供了原生支持,例如 GPU、FPGA、高性能 NIC 等等。