动态资源分配

特性状态: Kubernetes v1.34 [稳定] (默认启用:true)

本页面描述了 Kubernetes 中的**动态资源分配 (DRA)**。

关于 DRA

DRA 是 Kubernetes 的一项功能,它允许你在 Pod 之间请求和共享资源。这些资源通常是附加的设备,例如硬件加速器。

借助 DRA,设备驱动程序和集群管理员可以定义可供工作负载**声明**的设备**类**。Kubernetes 将匹配的设备分配给特定的声明,并将相应的 Pod 放置在可以访问所分配设备的节点上。

使用 DRA 分配资源与动态卷供应的体验类似,在动态卷供应中,你使用 PersistentVolumeClaims 从存储类中声明存储容量,并在 Pod 中请求所声明的容量。

DRA 的优势

DRA 提供了一种灵活的方式来对集群中的设备进行分类、请求和使用。使用 DRA 具有以下优势:

  • **灵活的设备过滤**:使用通用表达式语言 (CEL) 对特定设备属性执行细粒度过滤。
  • **设备共享**:通过引用相应的资源声明,与多个容器或 Pod 共享同一资源。
  • **集中式设备分类**:设备驱动程序和集群管理员可以使用设备类,为应用操作员提供针对各种用例优化的硬件类别。例如,你可以为通用工作负载创建成本优化设备类,为关键作业创建高性能设备类。
  • **简化的 Pod 请求**:借助 DRA,应用操作员无需在 Pod 资源请求中指定设备数量。相反,Pod 引用资源声明,该声明中的设备配置将应用于 Pod。

设备插件相比,这些优势显著改善了设备分配工作流程。设备插件需要按容器进行设备请求,不支持设备共享,也不支持基于表达式的设备过滤。

DRA 用户类型

使用 DRA 分配设备的工作流程涉及以下用户类型:

  • **设备所有者**:负责设备。设备所有者可能是商业供应商、集群操作员或其他实体。要使用 DRA,设备必须具有 DRA 兼容的驱动程序,这些驱动程序执行以下操作:

    • 创建 ResourceSlice,向 Kubernetes 提供节点和资源信息。
    • 当集群中的资源容量发生变化时更新 ResourceSlice。
    • (可选)创建 DeviceClass,工作负载操作员可以使用它来声明设备。
  • **集群管理员**:负责配置集群和节点、连接设备、安装驱动程序以及类似任务。要使用 DRA,集群管理员执行以下操作:

    • 将设备连接到节点。
    • 安装支持 DRA 的设备驱动程序。
    • (可选)创建 DeviceClass,工作负载操作员可以使用它来声明设备。
  • **工作负载操作员**:负责在集群中部署和管理工作负载。要使用 DRA 将设备分配给 Pod,工作负载操作员执行以下操作:

    • 创建 ResourceClaim 或 ResourceClaimTemplate,以请求 DeviceClass 中的特定配置。
    • 部署使用特定 ResourceClaim 或 ResourceClaimTemplate 的工作负载。

DRA 术语

DRA 使用以下 Kubernetes API 种类来提供核心分配功能。所有这些 API 种类都包含在 `resource.k8s.io/v1` API 组中。

DeviceClass
定义可声明的设备类别以及如何在声明中选择特定设备属性。DeviceClass 参数可以匹配 ResourceSlice 中零个或多个设备。要从 DeviceClass 声明设备,ResourceClaim 会选择特定的设备属性。
ResourceClaim
描述了对集群中附加资源(如设备)的访问请求。ResourceClaim 为 Pod 提供了对特定资源的访问权限。ResourceClaim 可以由工作负载操作员创建,也可以由 Kubernetes 根据 ResourceClaimTemplate 生成。
ResourceClaimTemplate
定义了一个模板,Kubernetes 使用它为工作负载创建每个 Pod 的 ResourceClaim。ResourceClaimTemplate 为 Pod 提供了对独立、配置相似的资源的访问权限。Kubernetes 从模板生成的每个 ResourceClaim 都绑定到特定的 Pod。当 Pod 终止时,Kubernetes 会删除相应的 ResourceClaim。
ResourceSlice
表示连接到节点的一个或多个资源,例如设备。驱动程序在集群中创建和管理 ResourceSlice。当 ResourceClaim 在 Pod 中创建和使用时,Kubernetes 使用 ResourceSlice 查找可以访问所声明资源的节点。Kubernetes 将资源分配给 ResourceClaim,并将 Pod 调度到可以访问资源的节点上。

DeviceClass

DeviceClass 允许集群管理员或设备驱动程序定义集群中的设备类别。DeviceClass 告诉操作员他们可以请求哪些设备以及如何请求这些设备。你可以使用通用表达式语言 (CEL) 根据特定属性选择设备。引用 DeviceClass 的 ResourceClaim 可以请求 DeviceClass 内的特定配置。

要创建 DeviceClass,请参阅在集群中设置 DRA

ResourceClaim 和 ResourceClaimTemplate

ResourceClaim 定义了工作负载所需的资源。每个 ResourceClaim 都有引用 DeviceClass 并从该 DeviceClass 中选择设备的**请求**。ResourceClaim 还可以使用**选择器**来筛选满足特定要求的设备,并可以使用**约束**来限制可以满足请求的设备。ResourceClaim 可以由工作负载操作员创建,也可以由 Kubernetes 根据 ResourceClaimTemplate 生成。ResourceClaimTemplate 定义了一个模板,Kubernetes 可以使用它为 Pod 自动生成 ResourceClaim。

ResourceClaim 和 ResourceClaimTemplate 的用例

你使用的方法取决于你的要求,具体如下:

  • **ResourceClaim**:你希望多个 Pod 共享对特定设备的访问。你手动管理你创建的 ResourceClaim 的生命周期。
  • **ResourceClaimTemplate**:你希望 Pod 独立访问单独的、配置相似的设备。Kubernetes 根据 ResourceClaimTemplate 中的规范生成 ResourceClaim。每个生成的 ResourceClaim 的生命周期都绑定到相应 Pod 的生命周期。

当你定义工作负载时,你可以使用通用表达式语言 (CEL)来过滤特定设备属性或容量。可用于过滤的参数取决于设备和驱动程序。

如果你在 Pod 中直接引用了特定的 ResourceClaim,那么该 ResourceClaim 必须已经存在于与 Pod 相同的命名空间中。如果 ResourceClaim 不存在于该命名空间中,则 Pod 将无法调度。此行为类似于 PersistentVolumeClaim 必须存在于引用它的 Pod 所在的相同命名空间中。

你可以在 Pod 中引用一个自动生成的 ResourceClaim,但不建议这样做,因为自动生成的 ResourceClaim 绑定到触发生成的 Pod 的生命周期。

要了解如何使用这些方法之一声明资源,请参阅使用 DRA 为工作负载分配设备

优先级列表

特性状态: Kubernetes v1.34 [beta] (默认启用:true)

你可以为 ResourceClaim 或 ResourceClaimTemplate 中的请求提供一个优先级排序的子请求列表。调度器将选择第一个可分配的子请求。这允许用户指定替代设备,如果首选设备不可用,工作负载可以使用这些替代设备。

在下面的示例中,ResourceClaimTemplate 请求了一个颜色为黑色、尺寸为大型的设备。如果具有这些属性的设备不可用,则 Pod 无法调度。通过优先级列表功能,可以指定第二个替代选项,该选项请求两个颜色为白色、尺寸为小型设备。如果大型黑色设备可用,则将分配它。如果不可用,但有两个小型白色设备可用,则 Pod 仍然可以运行。

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: prioritized-list-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        firstAvailable:
        - name: large-black
          deviceClassName: resource.example.com
          selectors:
          - cel:
              expression: |-
                device.attributes["resource-driver.example.com"].color == "black" &&
                device.attributes["resource-driver.example.com"].size == "large"                
        - name: small-white
          deviceClassName: resource.example.com
          selectors:
          - cel:
              expression: |-
                device.attributes["resource-driver.example.com"].color == "white" &&
                device.attributes["resource-driver.example.com"].size == "small"                
          count: 2

此决定是针对每个 Pod 做出的,因此,如果 Pod 是 ReplicaSet 或类似分组的成员,你不能依赖组的所有成员都选择相同的子请求。你的工作负载必须能够适应这种情况。

优先级列表是一个**Beta 特性**,在 kube-apiserver 和 kube-scheduler 中,通过 `DRAPrioritizedList` Feature Gate 默认启用。

ResourceSlice

每个 ResourceSlice 代表池中的一个或多个设备。该池由设备驱动程序管理,设备驱动程序创建和管理 ResourceSlice。池中的资源可以由单个 ResourceSlice 表示,也可以跨多个 ResourceSlice。

ResourceSlice 为设备用户和调度器提供有用的信息,对于动态资源分配至关重要。每个 ResourceSlice 必须包含以下信息:

  • **资源池**:驱动程序管理的一个或多个资源组。该池可以跨越多个 ResourceSlice。池中资源的变化必须传播到该池中的所有 ResourceSlice。管理该池的设备驱动程序负责确保这种传播发生。
  • **设备**:受管池中的设备。ResourceSlice 可以列出池中的所有设备或池中设备的一个子集。ResourceSlice 定义设备信息,例如属性、版本和容量。设备用户可以通过过滤 ResourceClaim 或 DeviceClass 中的设备信息来选择要分配的设备。
  • **节点**:可以访问资源的节点。驱动程序可以选择哪些节点可以访问资源,无论是集群中的所有节点、单个命名节点还是具有特定节点标签的节点。

驱动程序使用控制器来协调集群中的 ResourceSlice 与驱动程序必须发布的信息。此控制器会覆盖任何手动更改,例如集群用户创建或修改 ResourceSlice。

考虑以下 ResourceSlice 示例:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: cat-slice
spec:
  driver: "resource-driver.example.com"
  pool:
    generation: 1
    name: "black-cat-pool"
    resourceSliceCount: 1
  # The allNodes field defines whether any node in the cluster can access the device.
  allNodes: true
  devices:
  - name: "large-black-cat"
    attributes:
      color:
        string: "black"
      size:
        string: "large"
      cat:
        boolean: true

此 ResourceSlice 由 `black-cat-pool` 池中的 `resource-driver.example.com` 驱动程序管理。`allNodes: true` 字段表示集群中的任何节点都可以访问这些设备。ResourceSlice 中有一个名为 `large-black-cat` 的设备,具有以下属性:

  • `color`:`black`
  • `size`:`large`
  • `cat`:`true`

DeviceClass 可以通过使用这些属性来选择此 ResourceSlice,ResourceClaim 可以过滤该 DeviceClass 中的特定设备。

DRA 资源分配的工作原理

以下各节描述了各种DRA 用户类型以及 Kubernetes 系统在动态资源分配期间的工作流程。

用户工作流程

  1. **驱动程序创建**:设备所有者或第三方实体创建驱动程序,这些驱动程序可以在集群中创建和管理 ResourceSlice。这些驱动程序(可选)还会创建 DeviceClass,用于定义设备类别以及如何请求它们。
  2. **集群配置**:集群管理员创建集群,将设备连接到节点,并安装 DRA 设备驱动程序。集群管理员(可选)创建 DeviceClass,用于定义设备类别以及如何请求它们。
  3. **资源声明**:工作负载操作员创建 ResourceClaimTemplate 或 ResourceClaim,请求 DeviceClass 中的特定设备配置。在同一步骤中,工作负载操作员修改其 Kubernetes 清单以请求这些 ResourceClaimTemplate 或 ResourceClaim。

Kubernetes 工作流程

  1. **ResourceSlice 创建**:集群中的驱动程序创建 ResourceSlice,代表受管的类似设备池中的一个或多个设备。

  2. **工作负载创建**:集群控制平面检查新工作负载是否引用 ResourceClaimTemplate 或特定的 ResourceClaim。

    • 如果工作负载使用 ResourceClaimTemplate,则名为 `resourceclaim-controller` 的控制器会为工作负载中的每个 Pod 生成 ResourceClaim。
    • 如果工作负载使用特定的 ResourceClaim,Kubernetes 会检查该 ResourceClaim 是否存在于集群中。如果 ResourceClaim 不存在,则 Pod 将无法部署。
  3. **ResourceSlice 过滤**:对于每个 Pod,Kubernetes 检查集群中的 ResourceSlice,以查找满足以下所有条件的设备:

    • 可以访问资源的节点有资格运行该 Pod。
    • ResourceSlice 具有未分配的资源,与 Pod 的 ResourceClaim 的要求相匹配。
  4. **资源分配**:在为 Pod 的 ResourceClaim 找到符合条件的 ResourceSlice 后,Kubernetes 调度器会使用分配详细信息更新 ResourceClaim。

  5. **Pod 调度**:资源分配完成后,调度器将 Pod 放置在可以访问所分配资源的节点上。设备驱动程序和该节点上的 kubelet 会配置设备以及 Pod 对设备的访问权限。

动态资源的可观测性

你可以使用以下任何方法检查动态分配资源的状态:

kubelet 设备指标

`PodResourcesLister` kubelet gRPC 服务允许你监控正在使用的设备。`DynamicResource` 消息提供了特定于动态资源分配的信息,例如设备名称和声明名称。有关详细信息,请参阅监控设备插件资源

ResourceClaim 设备状态

功能状态: Kubernetes v1.33 [beta] (默认启用:true)

DRA 驱动程序可以在 ResourceClaim 的 `status.devices` 字段中报告每个已分配设备的特定于驱动程序的设备状态数据。例如,驱动程序可以列出分配给网络接口设备的 IP 地址。

驱动程序添加到 ResourceClaim `status.devices` 字段中的信息的准确性取决于驱动程序。评估驱动程序以确定你是否可以依赖此字段作为设备信息的唯一来源。

如果禁用 `DRAResourceClaimDeviceStatus` Feature Gate,则 `status.devices` 字段在存储 ResourceClaim 时会自动清除。当 DRA 驱动程序可以更新已设置 `status.devices` 字段的现有 ResourceClaim 时,支持 ResourceClaim 设备状态。

有关 `status.devices` 字段的详细信息,请参阅 ResourceClaim API 参考。

设备健康监测

特性状态: Kubernetes v1.31 [alpha] (默认禁用)

作为一项 Alpha 功能,Kubernetes 提供了一种机制来监控和报告动态分配的基础设施资源的健康状况。对于在专用硬件上运行的有状态应用程序,了解设备何时发生故障或变得不健康至关重要。了解设备是否恢复也很有帮助。

要启用此功能,必须启用 `ResourceHealthStatus` Feature Gate,并且 DRA 驱动程序必须实现 `DRAResourceHealth` gRPC 服务。

当 DRA 驱动程序检测到已分配设备变得不健康时,它会将此状态报告给 kubelet。然后,此健康信息直接暴露在 Pod 的状态中。kubelet 会在每个容器的状态中填充 `allocatedResourcesStatus` 字段,详细说明分配给该容器的每个设备的健康状况。

这为用户和控制器对硬件故障做出反应提供了关键的可见性。对于正在发生故障的 Pod,你可以检查此状态以确定故障是否与不健康的设备有关。

预调度 Pod

当你(或其他 API 客户端)创建 Pod 时,如果 `spec.nodeName` 已经设置,则调度器将被跳过。如果该 Pod 需要的某些 ResourceClaim 尚不存在,未分配或未为该 Pod 预留,则 kubelet 将无法运行该 Pod,并会定期重新检查,因为这些要求可能仍会在以后得到满足。

当 Pod 调度时(版本偏差、配置、Feature Gate 等),如果调度器中未启用动态资源分配支持,也可能出现这种情况。kube-controller-manager 会检测到这种情况,并尝试通过预留所需的 ResourceClaim 来使 Pod 可运行。然而,这仅适用于这些 ResourceClaim 已由调度器为其他 Pod 分配的情况。

最好避免跳过调度器,因为分配给节点的 Pod 会阻塞正常的资源(RAM、CPU),当 Pod 卡住时,这些资源无法用于其他 Pod。为了使 Pod 在特定节点上运行,同时仍通过正常的调度流程,请使用与所需节点完全匹配的节点选择器创建 Pod:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-cats
spec:
  nodeSelector:
    kubernetes.io/hostname: name-of-the-intended-node
  ...

你也可以在准入时修改传入的 Pod,取消设置 `.spec.nodeName` 字段,转而使用节点选择器。

DRA Beta 特性

以下各节描述了在 Beta 特性阶段可用的 DRA 特性。有关更多信息,请参阅在集群中设置 DRA

管理员访问

特性状态: Kubernetes v1.34 [beta] (默认启用:true)

你可以将 ResourceClaim 或 ResourceClaimTemplate 中的请求标记为具有特权功能,用于维护和故障排除任务。具有管理员访问权限的请求授予对正在使用的设备的访问权限,并可能在容器中使设备可用时启用额外的权限。

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: large-black-cat-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        exactly:
          deviceClassName: resource.example.com
          allocationMode: All
          adminAccess: true

如果此功能被禁用,则在创建此类 ResourceClaim 时,`adminAccess` 字段将自动删除。

管理员访问是一种特权模式,不应在多租户集群中授予普通用户。从 Kubernetes v1.33 开始,只有被授权在带有 `resource.k8s.io/admin-access: "true"`(区分大小写)标签的命名空间中创建 ResourceClaim 或 ResourceClaimTemplate 对象的用户才能使用 `adminAccess` 字段。这确保了非管理员用户不能滥用此功能。从 Kubernetes v1.34 开始,此标签已更新为 `resource.kubernetes.io/admin-access: "true"`。

DRA Alpha 特性

以下各节描述了在 Alpha 特性阶段可用的 DRA 特性。要使用这些特性中的任何一个,你还必须通过启用 DynamicResourceAllocation Feature Gate 和 DRA API 组来在集群中设置 DRA。有关更多信息,请参阅在集群中设置 DRA

DRA 的扩展资源分配

功能状态: Kubernetes v1.34 [alpha] (默认禁用)

你可以为 DeviceClass 提供一个扩展资源名称。调度器将为扩展资源请求选择与该类匹配的设备。这允许用户继续在 Pod 中使用扩展资源请求,以请求设备插件提供的扩展资源或 DRA 设备。同一扩展资源可以由设备插件或 DRA 在单个集群节点上提供。同一扩展资源可以由设备插件在某些节点上提供,由 DRA 在同一集群中的其他节点上提供。

在下面的示例中,DeviceClass 被赋予了扩展资源名称 `example.com/gpu`。如果一个 Pod 请求扩展资源 `example.com/gpu: 2`,它可以调度到具有两个或更多与 DeviceClass 匹配的设备的节点。

apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: gpu.example.com
spec:
  selectors:
  - cel:
      expression: device.driver == 'gpu.example.com' && device.attributes['gpu.example.com'].type
        == 'gpu'
  extendedResourceName: example.com/gpu

此外,用户可以使用一个特殊的扩展资源来分配设备,而无需显式创建 ResourceClaim。使用扩展资源名称前缀 `deviceclass.resource.kubernetes.io/` 和 DeviceClass 名称。这适用于任何 DeviceClass,即使它没有指定扩展资源名称。生成的 ResourceClaim 将包含对该 DeviceClass 的指定数量设备的 `ExactCount` 请求。

DRA 的扩展资源分配是一个**Alpha 特性**,仅当 kube-apiserver、kube-scheduler 和 kubelet 中启用了 `DRAExtendedResource` Feature Gate 时才启用。

可分区设备

特性状态: `Kubernetes v1.33 [alpha]`(默认启用:false)

DRA 中表示的设备不一定是一个连接到单个机器的单个单元,也可以是由连接到多个机器的多个设备组成的逻辑设备。这些设备可能会消耗底层物理设备的重叠资源,这意味着当一个逻辑设备被分配时,其他设备将不再可用。

在 ResourceSlice API 中,这表示为命名 CounterSets 的列表,每个 CounterSet 包含一组命名计数器。计数器表示物理设备上可用的资源,这些资源由通过 DRA 宣传的逻辑设备使用。

逻辑设备可以指定 ConsumesCounters 列表。每个条目包含对 CounterSet 的引用和一组命名的计数器以及它们将消耗的数量。因此,要使设备可分配,引用的 CounterSet 必须具有设备引用的计数器的足够数量。

下面是两个设备的示例,每个设备从共享计数器(8Gi 内存)中消耗 6Gi 内存。因此,在任何时间点,只有一个设备可以被分配。调度器处理此问题,并且对于消费者是透明的,因为 ResourceClaim API 不受影响。

kind: ResourceSlice
apiVersion: resource.k8s.io/v1
metadata:
  name: resourceslice
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 1
  driver: dra.example.com
  sharedCounters:
  - name: gpu-1-counters
    counters:
      memory:
        value: 8Gi
  devices:
  - name: device-1
    consumesCounters:
    - counterSet: gpu-1-counters
      counters:
        memory:
          value: 6Gi
  - name: device-2
    consumesCounters:
    - counterSet: gpu-1-counters
      counters:
        memory:
          value: 6Gi

可分区设备是一个**Alpha 特性**,仅当 kube-apiserver 和 kube-scheduler 中启用了 `DRAPartitionableDevices` Feature Gate 时才启用。

可消耗容量

功能状态: Kubernetes v1.34 [alpha] (默认禁用)

可消耗容量功能允许同一设备被多个独立的 ResourceClaims 消耗,Kubernetes 调度器管理每个声明使用了多少设备容量。这类似于 Pod 如何共享节点上的资源;ResourceClaims 可以共享设备上的资源。

设备驱动程序可以在 `ResourceSlice` 的 `.spec.devices` 中设置 `allowMultipleAllocations` 字段,以允许将该设备分配给多个独立的 ResourceClaims 或 ResourceClaim 中的多个请求。

用户可以在 `ResourceClaim` 的 `spec.devices.requests` 中设置 `capacity` 字段,以指定每个分配的设备资源要求。

对于允许多次分配的设备,请求的容量是从其总容量中提取或**消耗**的,这个概念被称为**可消耗容量**。然后,调度器确保所有声明的总消耗容量不超过设备的总体容量。此外,驱动程序作者可以在单个设备容量上使用 `requestPolicy` 约束来控制这些容量的消耗方式。例如,驱动程序作者可以指定给定的容量仅以 1Gi 的增量消耗。

这是一个网络设备的示例,它允许多次分配并包含可消耗的带宽容量。

kind: ResourceSlice
apiVersion: resource.k8s.io/v1
metadata:
  name: resourceslice
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 1
  driver: dra.example.com
  devices:
  - name: eth1
    allowMultipleAllocations: true
    attributes:
      name:
        string: "eth1"
    capacity:
      bandwidth:
        requestPolicy:
          default: "1M"
          validRange:
            min: "1M"
            step: "8"
        value: "10G"

可消耗容量可以按以下示例所示进行请求。

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: bandwidth-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        exactly:
        - deviceClassName: resource.example.com
          capacity:
            requests:
              bandwidth: 1G

分配结果将包括消耗的容量和份额标识符。

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
...
status:
  allocation:
    devices:
      results:
      - consumedCapacity:
          bandwidth: 1G
        device: eth1
        shareID: "a671734a-e8e5-11e4-8fde-42010af09327"

在此示例中,选择了一个可多重分配的设备。但是,任何至少具有请求的 1G 带宽的 `resource.example.com` 设备都可以满足要求。如果选择一个不可多重分配的设备,则分配将导致整个设备。要强制使用仅可多重分配的设备,可以使用 CEL 条件 `device.allowMultipleAllocations == true`。

设备污点和容忍度

特性状态: `Kubernetes v1.33 [alpha]`(默认启用:false)

设备污点类似于节点污点:污点具有字符串键、字符串值和效应。效应应用于使用被污点设备的 ResourceClaim 以及引用该 ResourceClaim 的所有 Pod。 “NoSchedule”效应阻止调度这些 Pod。当尝试分配 ResourceClaim 时,被污点设备将被忽略,因为使用它们将阻止 Pod 的调度。

“NoExecute”效应意味着“NoSchedule”,此外还会导致已调度所有 Pod 的逐出。这种逐出是由 kube-controller-manager 中的设备污点逐出控制器通过删除受影响的 Pod 来实现的。

ResourceClaims 可以容忍污点。如果污点被容忍,则其效应不适用。空容忍度匹配所有污点。容忍度可以限制为某些效应和/或匹配某些键/值对。容忍度可以检查某个键是否存在,无论其值如何,也可以检查键的特定值。有关此匹配的更多信息,请参阅节点污点概念

通过在一定时间内容忍污点,可以延迟逐出。该延迟从污点添加到设备的时间开始,该时间记录在污点的一个字段中。

污点如上所述也适用于分配节点上“所有”设备的 ResourceClaims。所有设备必须是无污点的,或者它们的所有污点都必须被容忍。分配具有管理员访问权限的设备(如上文所述)也不例外。使用该模式的管理员必须明确容忍所有污点才能访问被污点设备。

设备污点和容忍度是一个**Alpha 特性**,仅当 kube-apiserver、kube-controller-manager 和 kube-scheduler 中启用了 `DRADeviceTaints` Feature Gate 时才启用。要使用 DeviceTaintRules,必须启用 `resource.k8s.io/v1alpha3` API 版本。

你可以通过使用 DeviceTaintRule API 种类,以以下方式向设备添加污点。

驱动程序设置的污点

DRA 驱动程序可以向其在 ResourceSlice 中发布的设备信息添加污点。查阅 DRA 驱动程序的文档以了解驱动程序是否使用污点以及其键和值是什么。

管理员设置的污点

管理员或控制平面组件可以对设备施加污点,而无需告诉 DRA 驱动程序在其 ResourceSlice 的设备信息中包含污点。他们通过创建 DeviceTaintRule 来实现这一点。每个 DeviceTaintRule 会向匹配设备选择器的设备添加一个污点。如果没有这样的选择器,则不会对任何设备施加污点。这使得在不小心遗漏选择器时,意外逐出所有使用 ResourceClaim 的 Pod 变得更加困难。

可以通过给出 DeviceClass、驱动程序、池和/或设备的名称来选择设备。DeviceClass 选择该 DeviceClass 中选择器选择的所有设备。仅使用驱动程序名称,管理员可以对该驱动程序管理的所有设备施加污点,例如在整个集群中对该驱动程序进行某种维护时。添加池名称可以将污点限制到单个节点,如果驱动程序管理节点本地设备的话。

最后,添加设备名称可以选择一个特定设备。如果需要,设备名称和池名称也可以单独使用。例如,鼓励节点本地设备的驱动程序使用节点名称作为其池名称。然后,使用该池名称施加污点会自动对节点上的所有设备施加污点。

驱动程序可能会使用“gpu-0”等稳定名称,这些名称隐藏了当前分配给该名称的特定设备。为了支持对特定硬件实例施加污点,可以在 DeviceTaintRule 中使用 CEL 选择器来匹配供应商特定的唯一 ID 属性,如果驱动程序为其硬件支持该属性的话。

只要 DeviceTaintRule 存在,污点就适用。它可以随时修改和删除。这是一个虚构 DRA 驱动程序的 DeviceTaintRule 示例:

apiVersion: resource.k8s.io/v1alpha3
kind: DeviceTaintRule
metadata:
  name: example
spec:
  # The entire hardware installation for this
  # particular driver is broken.
  # Evict all pods and don't schedule new ones.
  deviceSelector:
    driver: dra.example.com
  taint:
    key: dra.example.com/unhealthy
    value: Broken
    effect: NoExecute

设备绑定条件

功能状态: Kubernetes v1.34 [alpha] (默认禁用)

设备绑定条件允许 Kubernetes 调度器延迟 Pod 绑定,直到确认外部资源(例如连接到网络的 GPU 或可编程 FPGA)已准备就绪。

这种等待行为在调度框架的PreBind 阶段实现。在此阶段,调度器会检查所有所需的设备条件是否满足,然后才继续绑定。

这通过避免过早绑定来提高调度可靠性,并能够与外部设备控制器协调。

要使用此功能,设备驱动程序(通常由驱动程序所有者管理)必须在 `ResourceSlice` 的 `Device` 部分发布以下字段。集群管理员必须启用 `DRADeviceBindingConditions` 和 `DRAResourceClaimDeviceStatus` Feature Gate,调度器才能识别这些字段。

  • `bindingConditions`:在 Pod 绑定之前,必须在关联 ResourceClaim 的 `status.conditions` 字段中设置为 `True` 的条件类型列表。这些通常表示就绪信号,例如“DeviceAttached”或“DeviceInitialized”。
  • `bindingFailureConditions`:如果关联 ResourceClaim 的 `status.conditions` 字段中设置为 `True`,则表示失败状态的条件类型列表。如果任何这些条件为 `True`,调度器将中止绑定并重新调度 Pod。
  • `bindsToNode`:如果设置为 `true`,调度器会将选定的节点名称记录在 ResourceClaim 的 `status.allocation.nodeSelector` 字段中。这不影响 Pod 的 `spec.nodeSelector`。相反,它在 ResourceClaim 内部设置一个节点选择器,外部控制器可以使用它来执行节点特定操作,例如设备连接或准备。

`bindingConditions` 和 `bindingFailureConditions` 中列出的所有条件类型都从 ResourceClaim 的 `status.conditions` 字段进行评估。外部控制器负责使用标准的 Kubernetes 条件语义(`type`、`status`、`reason`、`message`、`lastTransitionTime`)更新这些条件。

调度器最多等待 **600 秒**,直到所有 `bindingConditions` 变为 `True`。如果达到超时或任何 `bindingFailureConditions` 为 `True`,调度器将清除分配并重新调度 Pod。

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: gpu-slice
spec:
  driver: dra.example.com
  nodeSelector:
    accelerator-type: high-performance
  pool:
    name: gpu-pool
    generation: 1
    resourceSliceCount: 1
  devices:
    - name: gpu-1
      attributes:
        vendor:
          string: "example"
        model:
          string: "example-gpu"
      bindsToNode: true
      bindingConditions:
        - dra.example.com/is-prepared
      bindingFailureConditions:
        - dra.example.com/preparing-failed

此 ResourceSlice 示例具有以下属性:

  • ResourceSlice 以带有 `accelerator-type=high-performance` 标签的节点为目标,以便调度器仅使用一组特定的合格节点。
  • 调度器从选定组中选择一个节点(例如 `node-3`),并将 ResourceClaim 中的 `status.allocation.nodeSelector` 字段设置为该节点名称。
  • `dra.example.com/is-prepared` 绑定条件表示设备 `gpu-1` 必须在绑定之前准备好(`is-prepared` 条件的状态为 `True`)。
  • 如果 `gpu-1` 设备准备失败(`preparing-failed` 条件的状态为 `True`),调度器将中止绑定。
  • 调度器最多等待 600 秒,直到设备准备就绪。
  • 外部控制器可以使用 ResourceClaim 中的节点选择器,在选定的节点上执行节点特定设置。

下一步

上次修改时间为太平洋标准时间 2025 年 8 月 31 日凌晨 2:24:更新 DRA 术语 API 版本至 resource.k8s.io/v1 (8c2db7787f)