动态资源分配

使用结构化参数进行核心动态资源分配

功能状态: Kubernetes v1.30 [alpha]

使用控制平面控制器进行动态资源分配

功能状态: Kubernetes v1.26 [alpha]

动态资源分配是一种用于在 Pod 和 Pod 内容器之间请求和共享资源的 API。它是针对通用资源的持久卷 API 的概括。通常这些资源是诸如 GPU 之类的设备。

第三方资源驱动程序负责跟踪和准备资源,资源分配由 Kubernetes 通过结构化参数(在 Kubernetes 1.30 中引入)处理。不同类型的资源支持任意参数来定义需求和初始化。

当驱动程序提供控制平面控制器时,驱动程序本身会与 Kubernetes 调度程序协作处理分配。

开始之前

Kubernetes v1.31 包含针对动态资源分配的集群级 API 支持,但需要显式启用。您还必须为要使用此 API 管理的特定资源安装资源驱动程序。如果您没有运行 Kubernetes v1.31,请查看该版本的 Kubernetes 的文档。

API

resource.k8s.io/v1alpha3 API 组 提供以下类型

资源声明
描述对集群中资源的访问请求,供工作负载使用。例如,如果工作负载需要具有特定属性的加速器设备,这就是表达该请求的方式。状态段跟踪该声明是否已满足以及已分配了哪些特定资源。
资源声明模板
定义创建资源声明的规范和一些元数据。由用户在部署工作负载时创建。然后,Kubernetes 会自动创建和删除每个 Pod 的资源声明。
设备类
包含针对某些设备的预定义选择标准及其配置。设备类由集群管理员在安装资源驱动程序时创建。每个资源声明中分配设备的请求都必须引用一个设备类。
Pod 调度上下文
由控制平面和资源驱动程序在内部使用,用于协调 Pod 调度,当 Pod 需要为其分配资源声明,而这些资源声明使用控制平面控制器时。
资源切片
与结构化参数一起使用,以发布有关集群中可用资源的信息。

资源驱动程序的开发人员决定他们是否要使用控制平面控制器自己处理分配,或者依赖于 Kubernetes 通过结构化参数进行分配。自定义控制器提供了更大的灵活性,但集群自动扩展不会针对节点本地资源可靠地工作。结构化参数使集群自动扩展成为可能,但可能无法满足所有用例。

当驱动程序使用结构化参数时,所有选择设备的参数都在 ResourceClaim 和 DeviceClass 中使用树内类型定义。配置参数可以作为任意 JSON 对象嵌入其中。

core/v1 PodSpecresourceClaims 字段中定义 Pod 所需的资源声明。该列表中的条目引用资源声明或资源声明模板。在引用资源声明时,使用此 PodSpec(例如,在 Deployment 或 StatefulSet 中)的所有 Pod 共享同一个资源声明实例。在引用资源声明模板时,每个 Pod 都会获得自己的实例。

容器资源的resources.claims 列表定义容器是否可以访问这些资源实例,这使得在多个容器之间共享资源成为可能。

以下是一个虚构资源驱动程序的示例。将为该 Pod 创建两个资源声明对象,并且每个容器都可以访问其中一个。

apiVersion: resource.k8s.io/v1alpha3
kind: DeviceClass
name: resource.example.com
spec:
  selectors:
  - cel:
      expression: device.driver == "resource-driver.example.com"
---
apiVersion: resource.k8s.io/v1alpha2
kind: ResourceClaimTemplate
metadata:
  name: large-black-cat-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        deviceClassName: resource.example.com
        selectors:
        - cel:
           expression: |-
              device.attributes["resource-driver.example.com"].color == "black" &&
              device.attributes["resource-driver.example.com"].size == "large"              
–--
apiVersion: v1
kind: Pod
metadata:
  name: pod-with-cats
spec:
  containers:
  - name: container0
    image: ubuntu:20.04
    command: ["sleep", "9999"]
    resources:
      claims:
      - name: cat-0
  - name: container1
    image: ubuntu:20.04
    command: ["sleep", "9999"]
    resources:
      claims:
      - name: cat-1
  resourceClaims:
  - name: cat-0
    resourceClaimTemplateName: large-black-cat-claim-template
  - name: cat-1
    resourceClaimTemplateName: large-black-cat-claim-template

调度

使用控制平面控制器

与本机资源(CPU、RAM)和扩展资源(由设备插件管理,由 kubelet 公告)相比,如果没有结构化参数,调度程序将不知道集群中有哪些动态资源可用,或者如何将它们分割以满足特定资源声明的要求。资源驱动程序负责此项工作。当为其保留资源时,它们会将资源声明标记为“已分配”。这也告诉调度程序在集群中的哪个位置可以找到资源声明。

当 Pod 被调度时,调度程序会检查 Pod 所需的所有资源声明,并创建一个 PodScheduling 对象,在该对象中,它会通知负责这些资源声明的资源驱动程序,调度程序认为哪些节点适合该 Pod。资源驱动程序会通过排除没有足够驱动程序资源的节点来做出响应。调度程序获得此信息后,就会选择一个节点并将该选择存储在 PodScheduling 对象中。然后,资源驱动程序会分配其资源声明,以便资源在该节点上可用。完成后,Pod 将被调度。

作为此过程的一部分,资源声明也会为 Pod 保留。目前,资源声明可以由单个 Pod 独占使用,也可以由无限数量的 Pod 共享使用。

一个关键特性是,只有在 Pod 的所有资源都被分配和保留后,Pod 才会被调度到节点上。这避免了 Pod 被调度到一个节点,但随后无法在该节点上运行的情况,这是不好的,因为这样的待处理 Pod 还会阻塞为其预留的所有其他资源,如 RAM 或 CPU。

使用结构化参数

当驱动程序使用结构化参数时,调度程序会在 Pod 需要资源时承担为资源声明分配资源的责任。它是通过从 ResourceSlice 对象中检索可用资源的完整列表,跟踪哪些资源已分配给现有的资源声明,然后从剩余的资源中进行选择来实现的。

目前唯一支持的资源类型是设备。设备实例具有名称以及多个属性和容量。设备通过检查这些属性和容量的 CEL 表达式进行选择。此外,所选设备集也可以限制为满足某些约束条件的设备集。

选择的资源会与任何供应商特定的配置一起记录在资源声明状态中,因此当 Pod 即将在节点上启动时,节点上的资源驱动程序将拥有所有必要的信息来准备资源。

通过使用结构化参数,调度程序能够在不与任何 DRA 资源驱动程序通信的情况下做出决定。它还能够通过将有关资源声明分配的信息存储在内存中,并在后台将此信息写入资源声明对象(同时将 Pod 绑定到节点)来快速调度多个 Pod。

监控资源

kubelet 提供了一个 gRPC 服务,以支持发现正在运行的 Pod 的动态资源。有关 gRPC 端点的更多信息,请参见资源分配报告

预调度 Pod

当您(或其他 API 客户端)创建具有已设置的spec.nodeName 的 Pod 时,调度程序将被绕过。如果 Pod 所需的某些资源声明尚不存在、未分配或未为 Pod 保留,那么 kubelet 将无法运行 Pod,并且会定期重新检查,因为这些要求可能在以后得到满足。

当在调度 Pod 时,调度程序中未启用对动态资源分配的支持时(版本差异、配置、功能网关等),也会出现这种情况。kube-controller-manager 会检测到这种情况,并尝试通过触发分配和/或保留所需的资源声明来使 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 字段,并改为使用节点选择器。

启用动态资源分配

动态资源分配是一个alpha 功能,仅在DynamicResourceAllocation 功能网关resource.k8s.io/v1alpha3 API 组 启用时才启用。有关详细信息,请参见--feature-gates--runtime-config kube-apiserver 参数。kube-scheduler、kube-controller-manager 和 kubelet 也需要启用功能网关。

当资源驱动程序使用控制平面控制器时,除了DynamicResourceAllocation 之外,还需要启用DRAControlPlaneController 功能网关。

检查 Kubernetes 集群是否支持该功能的一种快速方法是使用以下命令列出 ResourceClass 对象:

kubectl get deviceclasses

如果您的集群支持动态资源分配,则响应将是设备类对象的列表,或者

No resources found

如果不支持,则会打印以下错误消息:

error: the server doesn't have a resource type "deviceclasses"

当可以创建spec.controller 字段已设置的资源声明时,支持控制平面控制器。当DRAControlPlaneController 功能禁用时,该字段在存储资源声明时会自动被清除。

kube-scheduler 的默认配置在启用功能网关时以及使用 v1 配置 API 时启用“DynamicResources”插件。自定义配置可能需要修改才能包含它。

除了在集群中启用该功能外,还需要安装资源驱动程序。有关详细信息,请参阅驱动程序文档。

下一步

上次修改时间:2024 年 6 月 14 日,太平洋标准时间上午 10:03:DRA:更新至 1.31 (5b40c51031)