# DRA P1：DRA 能解决什么问题？从部署到使用的完整体验



![dra-p1.jpg](https://img.lixueduan.com/kubernetes/cover/dra-p1.jpg)

在 Kubernetes 里用 GPU 这类设备，大家习惯走 DevicePlugin。但 AI workload 越来越复杂，DevicePlugin 的短板越来越明显——**没法描述设备属性，调度器不参与分配，Pod 经常调度到节点后才发现资源不够**。

DRA（Dynamic Resource Allocation，动态资源分配）就是 Kubernetes 针对这些问题推出的新框架。

<!--more-->

**DRA 核心功能在 Kubernetes 1.34 已 GA**，可以放心用在生产环境。



## 1. DRA 解决什么问题？

### DevicePlugin 的局限性

* 只能上报"数量"，无法描述设备属性

* 调度器不参与分配，导致调度冲突

* 不支持资源预留



### DRA 的核心改进

* 设备信息通过 ResourceSlice 进入 API Server，调度器可见

* 精确的设备选择（通过 CEL 表达式）

* 支持资源预留和共享



例如：

**DevicePlugin**：用户申请 1 个 GPU → 调度器随机选节点 → Kubelet 本地分配 -> Pod 启动后发现显存不够 OOM（比如你想要 A100 80GB，但被调度到了只有 V100 16GB 的节点，因为调度器无法区分 GPU 型号）

**DRA**：用户显式申请一个"显存>40Gi 的 GPU" → 调度器精确匹配 → 预分配成功 → Pod  正常启动

![DevicePlugin vs DRA 对比](https://img.lixueduan.com/kubernetes/dra/dra-p1-compare.png)

## 2. 部署环境

### 2.1 前置条件

* K8s 相关：

  * Kubernetes v1.32 or newer.

  * DRA and corresponding API groups must be enabled.

* 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 冲突。



安装命令如下：

```bash
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
```

核心参数

```bash
# 关闭 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 都是用不上这个功能的，默认关闭即可




安装命令如下：

```bash
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](https://github.com/kubernetes/enhancements/blob/master/keps/sig-scheduling/5004-dra-extended-resource/README.md) 正式发布之前，**resources.gpus.enabled=true的 DRA 驱动无法与标准的 NVIDIA GPU DevicePlugin 同时安装**。两者会因管理相同的扩展资源（nvidia.com/gpu）而发生冲突。

> 可以通过 `--set 'gpuResourcesEnabledOverride=true'` 安装。



核心参数：

```bash
# 开启 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。

```bash
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 资源

```bash
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` 为例，查看详情：

```yaml
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
```

![ResourceSlice 库存表](https://img.lixueduan.com/kubernetes/dra/dra-p1-resourceslice.png)

里面记录了节点上所有 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`则定义了如何使用这些资源的‘筛选规则’。

```bash
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 内容如下：

```Bash
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 定义规则

```Bash
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

```yaml
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 指定名称进行关联。

```yaml
# 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 验证

验证调度结果

```bash
# 查看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 状态和调度节点

```bash
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 详情

```bash
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：

```bash
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 等等。

---

> 作者: [意琦行](https://github.com/lixd)  
> URL: https://www.lixueduan.com/posts/kubernetes/54-dra-p1-quickstart/  

