使用 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 组中)共享信息,其中包括 DeviceClassesResourceSlicesResourceClaims,以及 Pod 规约本身中的新字段。

目标

  • 部署示例 DRA 驱动程序
  • 使用 DRA API 部署请求硬件声明的 Pod
  • 删除具有声明的 Pod

准备工作

你的集群应该支持 RBAC。你可以在使用不同授权机制的集群上尝试本教程,但在这种情况下,你需要调整关于定义角色和权限的步骤。

你需要一个 Kubernetes 集群,并且 kubectl 命令行工具必须配置为与你的集群通信。建议在至少有两个不是控制平面主机的节点组成的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者你可以使用这些 Kubernetes 操场之一。

本教程已在 Linux 节点上进行测试,但可能也适用于其他类型的节点。

你的 Kubernetes 服务器版本必须是 v1.34。

要检查版本,请输入 kubectl version

如果你的集群目前没有运行 Kubernetes 1.34,请查阅你计划使用的 Kubernetes 版本的文档。

探索初始集群状态

你可以花一些时间观察已启用 DRA 的集群的初始状态,特别是如果你以前没有广泛使用过这些 API。如果你为本教程设置了一个新集群,但未安装驱动程序且尚未满足 Pod 声明,则这些命令的输出将不显示任何资源。

  1. 获取 DeviceClasses 列表

    kubectl get deviceclasses
    

    输出类似于:

    No resources found
    
  2. 获取 ResourceSlices 列表

    kubectl get resourceslices
    

    输出类似于:

    No resources found
    
  3. 获取 ResourceClaimsResourceClaimTemplates 列表

    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 的命名空间

  1. 创建命名空间

    kubectl create namespace dra-tutorial 
    

在生产环境中,你可能会使用驱动程序供应商或你自己的组织发布的或经过验证的镜像,并且你的节点需要能够访问托管驱动程序镜像的镜像仓库。在本教程中,你将使用 dra-example-driver 的公共发布镜像来模拟访问 DRA 驱动程序镜像。

  1. 通过在集群中的一个节点内运行以下命令来确认你的节点可以访问该镜像

    docker pull registry.k8s.io/dra-example-driver/dra-example-driver:v0.2.0
    

部署 DRA 驱动程序组件

对于本教程,你将使用 kubectl 单独安装关键的示例资源驱动程序组件。

  1. 创建表示此 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
    
  2. 创建 ServiceAccount、ClusterRole 和 ClusterRoleBinding,驱动程序将使用它们来获得与此集群上的 Kubernetes API 交互的权限。

    1. 创建服务账号

      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-driver
      kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/serviceaccount.yaml
      
    2. 创建集群角色

      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
      
    3. 创建集群角色绑定

      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.io
      kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/clusterrolebinding.yaml
      
  3. 为 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
    
  4. 部署实际的 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/cdi
    kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/daemonset.yaml
    

    DaemonSet 配置了必要的卷挂载,用于与底层容器设备接口 (CDI) 目录交互,并通过 kubelet/plugins 目录将其套接字暴露给 kubelet

验证 DRA 驱动程序安装

  1. 获取所有工作节点上 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
    
  2. 每个节点的本地 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-gpu
kubectl apply --server-side -f http://k8s.io/examples/dra/driver-install/example/pod.yaml
  1. 确认 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。

  1. 检查 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"
    
  2. 检查 ResourceClaim 对象的状态

    kubectl get resourceclaims -n dra-tutorial
    

    输出类似于:

    NAME       STATE                AGE
    some-gpu   allocated,reserved   34s
    

    在此输出中,STATE 列显示 ResourceClaim 已分配并保留。

  3. 检查 some-gpu ResourceClaim 的详细信息。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

  4. 要检查驱动程序如何处理设备分配,请获取驱动程序 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 和驱动程序的相应更改。

  1. 删除 pod0 Pod

    kubectl delete pod pod0 -n dra-tutorial
    

    输出类似于:

    pod "pod0" deleted
    

观察 DRA 状态

当 Pod 被删除时,驱动程序会从 ResourceClaim 中解除分配设备,并更新 Kubernetes API 中的 ResourceClaim 资源。ResourceClaim 处于 pending 状态,直到在新的 Pod 中引用它。

  1. 检查 some-gpu ResourceClaim 的状态

    kubectl get resourceclaims -n dra-tutorial
    

    输出类似于:

    NAME       STATE     AGE
    some-gpu   pending   76s
    
  2. 通过检查驱动程序日志,验证驱动程序已处理此声明的设备解除准备操作。

    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

下一步

最后修改于太平洋标准时间 2025 年 8 月 27 日上午 4:08:修复镜像标签拼写错误,简化前提条件 (b5ca1c9e43)