使用 DRA 安装驱动程序并分配设备
Kubernetes v1.34 [稳定] (默认启用:true)本教程将向你展示如何在集群中安装动态资源分配 (DRA) 驱动程序,以及如何结合 DRA API 使用它们将设备分配给 Pod。本页面适用于集群管理员。
动态资源分配 (DRA) 允许集群管理硬件资源的可用性和分配,以满足基于 Pod 的硬件需求和偏好声明。为了支持这一点,Kubernetes 内置组件(如 Kubernetes 调度器、kubelet 和 kube-controller-manager)和设备所有者提供的第三方驱动程序(称为 DRA 驱动程序)共同负责在 Pod 生命周期中通告、分配、准备、挂载、健康检查、解除准备和清理资源。这些组件通过一系列 DRA 特定的 API(位于 resource.k8s.io API 组中)共享信息,其中包括 DeviceClasses、ResourceSlices、ResourceClaims,以及 Pod 规约本身中的新字段。
目标
- 部署示例 DRA 驱动程序
- 使用 DRA API 部署请求硬件声明的 Pod
- 删除具有声明的 Pod
准备工作
你的集群应该支持 RBAC。你可以在使用不同授权机制的集群上尝试本教程,但在这种情况下,你需要调整关于定义角色和权限的步骤。
你需要一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与你的集群通信。建议在至少有两个不是控制平面主机的节点组成的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者你可以使用这些 Kubernetes 操场之一。
本教程已在 Linux 节点上进行测试,但可能也适用于其他类型的节点。
你的 Kubernetes 服务器版本必须是 v1.34。要检查版本,请输入 kubectl version。
如果你的集群目前没有运行 Kubernetes 1.34,请查阅你计划使用的 Kubernetes 版本的文档。
探索初始集群状态
你可以花一些时间观察已启用 DRA 的集群的初始状态,特别是如果你以前没有广泛使用过这些 API。如果你为本教程设置了一个新集群,但未安装驱动程序且尚未满足 Pod 声明,则这些命令的输出将不显示任何资源。
获取 DeviceClasses 列表
kubectl get deviceclasses输出类似于:
No resources found获取 ResourceSlices 列表
kubectl get resourceslices输出类似于:
No resources found获取 ResourceClaims 和 ResourceClaimTemplates 列表
kubectl get resourceclaims -A kubectl get resourceclaimtemplates -A输出类似于:
No resources found No resources found
至此,你已确认 DRA 在集群中已启用并正确配置,并且尚未有任何 DRA 驱动程序向 DRA API 通告任何资源。
安装示例 DRA 驱动程序
DRA 驱动程序是运行在集群每个节点上的第三方应用程序,用于与该节点的硬件和 Kubernetes 内置的 DRA 组件进行接口。安装过程取决于你选择的驱动程序,但很可能以 DaemonSet 的形式部署到集群中的所有节点或选定的节点(使用选择器或类似机制)。
请查阅驱动程序的文档以获取具体的安装说明,其中可能包括 Helm chart、一组清单或其他部署工具。
本教程使用 kubernetes-sigs/dra-example-driver 仓库中的示例驱动程序来演示驱动程序安装。这个示例驱动程序向 Kubernetes 通告模拟 GPU,供你的 Pod 与之交互。
准备集群以进行驱动程序安装
为了简化清理,创建一个名为 dra-tutorial 的命名空间
创建命名空间
kubectl create namespace dra-tutorial
在生产环境中,你可能会使用驱动程序供应商或你自己的组织发布的或经过验证的镜像,并且你的节点需要能够访问托管驱动程序镜像的镜像仓库。在本教程中,你将使用 dra-example-driver 的公共发布镜像来模拟访问 DRA 驱动程序镜像。
通过在集群中的一个节点内运行以下命令来确认你的节点可以访问该镜像
docker pull registry.k8s.io/dra-example-driver/dra-example-driver:v0.2.0
部署 DRA 驱动程序组件
对于本教程,你将使用 kubectl 单独安装关键的示例资源驱动程序组件。
创建表示此 DRA 驱动程序支持的设备类型的 DeviceClass
apiVersion: resource.k8s.io/v1 kind: DeviceClass metadata: name: gpu.example.com spec: selectors: - cel: expression: "device.driver == 'gpu.example.com'"kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/deviceclass.yaml创建 ServiceAccount、ClusterRole 和 ClusterRoleBinding,驱动程序将使用它们来获得与此集群上的 Kubernetes API 交互的权限。
创建服务账号
apiVersion: v1 kind: ServiceAccount metadata: name: dra-example-driver-service-account namespace: dra-tutorial labels: app.kubernetes.io/name: dra-example-driver app.kubernetes.io/instance: dra-example-driverkubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/serviceaccount.yaml创建集群角色
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: dra-example-driver-role rules: - apiGroups: ["resource.k8s.io"] resources: ["resourceclaims"] verbs: ["get"] - apiGroups: [""] resources: ["nodes"] verbs: ["get"] - apiGroups: ["resource.k8s.io"] resources: ["resourceslices"] verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/clusterrole.yaml创建集群角色绑定
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: dra-example-driver-role-binding subjects: - kind: ServiceAccount name: dra-example-driver-service-account namespace: dra-tutorial roleRef: kind: ClusterRole name: dra-example-driver-role apiGroup: rbac.authorization.k8s.iokubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/clusterrolebinding.yaml
为 DRA 驱动程序创建一个 PriorityClass。PriorityClass 可防止 DRA 驱动程序组件被抢占,该组件负责 Pod 生命周期中的重要操作。在此处了解有关 Pod 优先级和抢占的更多信息。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: dra-driver-high-priority value: 1000000 globalDefault: false description: "This priority class should be used for DRA driver pods only."kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/priorityclass.yaml部署实际的 DRA 驱动程序作为一个 DaemonSet,配置为使用上面提供的权限运行示例驱动程序二进制文件。DaemonSet 具有你在前几个步骤中授予 ServiceAccount 的权限。
apiVersion: apps/v1 kind: DaemonSet metadata: name: dra-example-driver-kubeletplugin namespace: dra-tutorial labels: app.kubernetes.io/name: dra-example-driver spec: selector: matchLabels: app.kubernetes.io/name: dra-example-driver updateStrategy: type: RollingUpdate template: metadata: labels: app.kubernetes.io/name: dra-example-driver spec: priorityClassName: dra-driver-high-priority serviceAccountName: dra-example-driver-service-account securityContext: {} containers: - name: plugin securityContext: privileged: true image: registry.k8s.io/dra-example-driver/dra-example-driver:v0.2.0 imagePullPolicy: IfNotPresent command: ["dra-example-kubeletplugin"] resources: {} # Production drivers should always implement a liveness probe # For the tutorial we simply omit it # livenessProbe: # grpc: # port: 51515 # service: liveness # failureThreshold: 3 # periodSeconds: 10 env: - name: CDI_ROOT value: /var/run/cdi - name: KUBELET_REGISTRAR_DIRECTORY_PATH value: "/var/lib/kubelet/plugins_registry" - name: KUBELET_PLUGINS_DIRECTORY_PATH value: "/var/lib/kubelet/plugins" - name: NODE_NAME valueFrom: fieldRef: fieldPath: spec.nodeName - name: NAMESPACE valueFrom: fieldRef: fieldPath: metadata.namespace # Simulated number of devices the example driver will pretend to have. - name: NUM_DEVICES value: "9" - name: HEALTHCHECK_PORT value: "51515" volumeMounts: - name: plugins-registry mountPath: "/var/lib/kubelet/plugins_registry" - name: plugins mountPath: "/var/lib/kubelet/plugins" - name: cdi mountPath: /var/run/cdi volumes: - name: plugins-registry hostPath: path: "/var/lib/kubelet/plugins_registry" - name: plugins hostPath: path: "/var/lib/kubelet/plugins" - name: cdi hostPath: path: /var/run/cdikubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/daemonset.yamlDaemonSet 配置了必要的卷挂载,用于与底层容器设备接口 (CDI) 目录交互,并通过
kubelet/plugins目录将其套接字暴露给kubelet。
验证 DRA 驱动程序安装
获取所有工作节点上 DRA 驱动程序 DaemonSet 的 Pod 列表
kubectl get pod -l app.kubernetes.io/name=dra-example-driver -n dra-tutorial输出类似于:
NAME READY STATUS RESTARTS AGE dra-example-driver-kubeletplugin-4sk2x 1/1 Running 0 13s dra-example-driver-kubeletplugin-cttr2 1/1 Running 0 13s每个节点的本地 DRA 驱动程序的初始职责是更新集群中可供 Pod 使用的设备,方法是将其元数据发布到 ResourceSlices API。你可以检查该 API,查看每个带有驱动程序的节点都在通告其所代表的设备类。
检查可用的 ResourceSlices
kubectl get resourceslices输出类似于:
NAME NODE DRIVER POOL AGE kind-worker-gpu.example.com-k69gd kind-worker gpu.example.com kind-worker 19s kind-worker2-gpu.example.com-qdgpn kind-worker2 gpu.example.com kind-worker2 19s
至此,你已成功安装了示例 DRA 驱动程序,并确认了其初始配置。现在你可以使用 DRA 调度 Pod 了。
声明资源并部署 Pod
要使用 DRA 请求资源,你需要创建 ResourceClaims 或 ResourceClaimTemplates,它们定义了你的 Pod 所需的资源。在示例驱动程序中,为模拟 GPU 设备公开了一个内存容量属性。本节将向你展示如何使用 通用表达式语言 在 ResourceClaim 中表达你的需求,在 Pod 规范中选择该 ResourceClaim,并观察资源分配。
本教程仅展示一个基本的 DRA ResourceClaim 示例。阅读 动态资源分配 以了解更多关于 ResourceClaim 的信息。
创建 ResourceClaim
在本节中,你将创建一个 ResourceClaim 并在 Pod 中引用它。无论声明如何,deviceClassName 都是一个必需字段,它将请求的范围缩小到特定的设备类。请求本身可以包含一个 通用表达式语言 表达式,该表达式引用管理该设备类的驱动程序可能通告的属性。
在此示例中,你将创建一个请求,要求任何通告超过 10Gi 内存容量的 GPU。从示例驱动程序公开容量的属性形式为 device.capacity['gpu.example.com'].memory。另请注意,声明的名称设置为 some-gpu。
apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
name: some-gpu
namespace: dra-tutorial
spec:
devices:
requests:
- name: some-gpu
exactly:
deviceClassName: gpu.example.com
selectors:
- cel:
expression: "device.capacity['gpu.example.com'].memory.compareTo(quantity('10Gi')) >= 0"kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/example/resourceclaim.yaml
创建引用该 ResourceClaim 的 Pod
下面是 Pod 清单,它在 spec.resourceClaims.resourceClaimName 字段中引用了你刚刚创建的 ResourceClaim some-gpu。然后,该声明的本地名称 gpu 用于 spec.containers.resources.claims.name 字段,以将声明分配给 Pod 的底层容器。
apiVersion: v1
kind: Pod
metadata:
name: pod0
namespace: dra-tutorial
labels:
app: pod
spec:
containers:
- name: ctr0
image: ubuntu:24.04
command: ["bash", "-c"]
args: ["export; trap 'exit 0' TERM; sleep 9999 & wait"]
resources:
claims:
- name: gpu
resourceClaims:
- name: gpu
resourceClaimName: some-gpukubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/example/pod.yaml
确认 Pod 已部署
kubectl get pod pod0 -n dra-tutorial输出类似于:
NAME READY STATUS RESTARTS AGE pod0 1/1 Running 0 9s
探索 DRA 状态
创建 Pod 后,集群会尝试将该 Pod 调度到 Kubernetes 可以满足 ResourceClaim 的节点。在本教程中,DRA 驱动程序部署在所有节点上,并在所有节点上通告模拟 GPU,所有这些 GPU 都通告了足够的容量来满足 Pod 的声明,因此 Kubernetes 可以将此 Pod 调度到任何节点,并可以分配该节点上的任何模拟 GPU。
当 Kubernetes 将模拟 GPU 分配给 Pod 时,示例驱动程序会在每个分配给它的容器中添加环境变量,以指示真正的资源驱动程序将会注入哪些 GPU 以及如何配置它们,因此你可以检查这些环境变量以查看系统如何处理 Pod。
检查 Pod 日志,其中报告了已分配的模拟 GPU 的名称
kubectl logs pod0 -c ctr0 -n dra-tutorial | grep -E "GPU_DEVICE_[0-9]+=" | grep -v "RESOURCE_CLAIM"输出类似于:
declare -x GPU_DEVICE_0="gpu-0"检查 ResourceClaim 对象的状态
kubectl get resourceclaims -n dra-tutorial输出类似于:
NAME STATE AGE some-gpu allocated,reserved 34s在此输出中,
STATE列显示 ResourceClaim 已分配并保留。检查
some-gpuResourceClaim 的详细信息。ResourceClaim 的status节包含有关已分配设备及其已保留的 Pod 的信息。kubectl get resourceclaim some-gpu -n dra-tutorial -o yaml输出类似于:
1apiVersion: resource.k8s.io/v1 2kind: ResourceClaim 3metadata: 4 creationTimestamp: "2025-08-20T18:17:31Z" 5 finalizers: 6 - resource.kubernetes.io/delete-protection 7 name: some-gpu 8 namespace: dra-tutorial 9 resourceVersion: "2326" 10 uid: d3e48dbf-40da-47c3-a7b9-f7d54d1051c3 11spec: 12 devices: 13 requests: 14 - exactly: 15 allocationMode: ExactCount 16 count: 1 17 deviceClassName: gpu.example.com 18 selectors: 19 - cel: 20 expression: device.capacity['gpu.example.com'].memory.compareTo(quantity('10Gi')) 21 >= 0 22 name: some-gpu 23status: 24 allocation: 25 devices: 26 results: 27 - device: gpu-0 28 driver: gpu.example.com 29 pool: kind-worker 30 request: some-gpu 31 nodeSelector: 32 nodeSelectorTerms: 33 - matchFields: 34 - key: metadata.name 35 operator: In 36 values: 37 - kind-worker 38 reservedFor: 39 - name: pod0 40 resource: pods 41 uid: c4dadf20-392a-474d-a47b-ab82080c8bd7要检查驱动程序如何处理设备分配,请获取驱动程序 DaemonSet Pod 的日志
kubectl logs -l app.kubernetes.io/name=dra-example-driver -n dra-tutorial输出类似于:
I0820 18:17:44.131324 1 driver.go:106] PrepareResourceClaims is called: number of claims: 1 I0820 18:17:44.135056 1 driver.go:133] Returning newly prepared devices for claim 'd3e48dbf-40da-47c3-a7b9-f7d54d1051c3': [{[some-gpu] kind-worker gpu-0 [k8s.gpu.example.com/gpu=common k8s.gpu.example.com/gpu=d3e48dbf-40da-47c3-a7b9-f7d54d1051c3-gpu-0]}]
你现在已经成功部署了一个使用 DRA 声明设备的 Pod,验证了该 Pod 已调度到合适的节点,并看到相关的 DRA API 种类已更新为分配状态。
删除具有声明的 Pod
当带有声明的 Pod 被删除时,DRA 驱动程序会解除分配资源,以便将来可以用于调度。为了验证此行为,请删除你在前几个步骤中创建的 Pod,并观察 ResourceClaim 和驱动程序的相应更改。
删除
pod0Podkubectl delete pod pod0 -n dra-tutorial输出类似于:
pod "pod0" deleted
观察 DRA 状态
当 Pod 被删除时,驱动程序会从 ResourceClaim 中解除分配设备,并更新 Kubernetes API 中的 ResourceClaim 资源。ResourceClaim 处于 pending 状态,直到在新的 Pod 中引用它。
检查
some-gpuResourceClaim 的状态kubectl get resourceclaims -n dra-tutorial输出类似于:
NAME STATE AGE some-gpu pending 76s通过检查驱动程序日志,验证驱动程序已处理此声明的设备解除准备操作。
kubectl logs -l app.kubernetes.io/name=dra-example-driver -n dra-tutorial输出类似于:
I0820 18:22:15.629376 1 driver.go:138] UnprepareResourceClaims is called: number of claims: 1
你现在已删除一个带有声明的 Pod,并观察到驱动程序采取了行动来解除底层硬件资源的准备,并更新 DRA API 以反映该资源再次可用于将来的调度。
清理
要清理你在本教程中创建的资源,请按照以下步骤操作
kubectl delete namespace dra-tutorial
kubectl delete deviceclass gpu.example.com
kubectl delete clusterrole dra-example-driver-role
kubectl delete clusterrolebinding dra-example-driver-role-binding
kubectl delete priorityclass dra-driver-high-priority