动态资源分配

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

动态资源分配是一种用于在 Pod 和 Pod 内的容器之间请求和共享资源的 API。它是针对通用资源的持久卷 API 的泛化。第三方资源驱动程序负责跟踪和分配资源,Kubernetes 通过*结构化参数*(在 Kubernetes 1.30 中引入)提供额外支持。当驱动程序使用结构化参数时,Kubernetes 无需与驱动程序通信即可处理调度和资源分配。不同类型的资源支持任意参数来定义需求和初始化。

在你开始之前

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

API

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

ResourceClass
定义哪个资源驱动程序处理某种类型的资源,并为其提供通用参数。ResourceClass 由集群管理员在安装资源驱动程序时创建。
ResourceClaim
定义工作负载所需的特定资源实例。由用户创建(生命周期手动管理,可以在不同 Pod 之间共享)或由控制平面根据 ResourceClaimTemplate 为单个 Pod 创建(自动生命周期,通常仅由一个 Pod 使用)。
ResourceClaimTemplate
定义用于创建 ResourceClaim 的规范和一些元数据。由用户在部署工作负载时创建。
PodSchedulingContext
由控制平面和资源驱动程序在需要为 Pod 分配 ResourceClaim 时,在内部用于协调 Pod 调度。
ResourceSlice
与结构化参数一起使用,以发布有关集群中可用资源的信息。
ResourceClaimParameters
以 Kubernetes 理解的格式(“结构化参数模型”)包含影响调度的 ResourceClaim 参数。其他参数可以嵌入到不透明扩展中,供供应商驱动程序在设置底层资源时使用。
ResourceClassParameters
与 ResourceClaimParameters 类似,ResourceClassParameters 为 Kubernetes 理解的 ResourceClass 参数提供了一种类型。

ResourceClass 和 ResourceClaim 的参数存储在单独的对象中,通常使用在安装资源驱动程序时创建的 CRD 定义的类型。

资源驱动程序的开发者决定是希望在自己外部的控制器中处理这些参数,还是希望 Kubernetes 通过使用结构化参数来处理它们。自定义控制器提供了更大的灵活性,但集群自动缩放无法可靠地用于节点本地资源。结构化参数支持集群自动缩放,但可能无法满足所有用例。

当驱动程序使用结构化参数时,仍然可以让最终用户使用特定于供应商的 CRD 指定参数。这样做时,驱动程序需要将这些自定义参数转换为树内类型。或者,驱动程序也可以记录如何直接使用树内类型。

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

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

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

apiVersion: resource.k8s.io/v1alpha2
kind: ResourceClass
name: resource.example.com
driverName: resource-driver.example.com
---
apiVersion: cats.resource.example.com/v1
kind: ClaimParameters
name: large-black-cat-claim-parameters
spec:
  color: black
  size: large
---
apiVersion: resource.k8s.io/v1alpha2
kind: ResourceClaimTemplate
metadata:
  name: large-black-cat-claim-template
spec:
  spec:
    resourceClassName: resource.example.com
    parametersRef:
      apiGroup: cats.resource.example.com
      kind: ClaimParameters
      name: large-black-cat-claim-parameters
–--
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
    source:
      resourceClaimTemplateName: large-black-cat-claim-template
  - name: cat-1
    source:
      resourceClaimTemplateName: large-black-cat-claim-template

调度

没有结构化参数

与原生资源(CPU、RAM)和扩展资源(由设备插件管理,由 kubelet 公告)相比,如果没有结构化参数,调度器就不知道集群中有哪些动态资源可用,或者如何拆分这些资源来满足特定 ResourceClaim 的需求。资源驱动程序负责这一点。它们会在为 ResourceClaim 保留资源后将其标记为“已分配”。这也告诉调度器 ResourceClaim 在集群中的哪个位置可用。

ResourceClaim 可以在创建后立即分配(“立即分配”),而无需考虑哪些 Pod 将使用它们。默认情况下,分配会延迟到调度需要 ResourceClaim 的 Pod 时(即“等待第一个使用者”)。

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

作为此过程的一部分,还会为 Pod 保留 ResourceClaim。目前,ResourceClaim 可以由单个 Pod 独占使用,也可以由无限数量的 Pod 使用。

一个关键特性是,除非所有资源都已分配和保留,否则 Pod 不会被调度到节点。这避免了 Pod 被调度到一个节点然后无法在该节点上运行的情况,这种情况很糟糕,因为这样的待处理 Pod 也会阻塞为其预留的所有其他资源,例如 RAM 或 CPU。

使用结构化参数

当驱动程序使用结构化参数时,调度器会在 Pod 需要资源时接管将资源分配给 ResourceClaim 的责任。它通过从 ResourceSlice 对象检索可用资源的完整列表、跟踪哪些资源已分配给现有 ResourceClaim,然后从剩余资源中进行选择来做到这一点。所选的确切资源受与 ResourceClaim 关联的任何 ResourceClaimParameters 或 ResourceClassParameters 中提供的约束的限制。

所选资源与任何特定于供应商的参数一起记录在 ResourceClaim 状态中,因此当 Pod 即将在节点上启动时,节点上的资源驱动程序就拥有准备资源所需的所有信息。

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

监控资源

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

预定 Pod

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

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

启用动态资源分配

动态资源分配是一项 Alpha 功能,仅当启用了 DynamicResourceAllocation 功能门控resource.k8s.io/v1alpha2 API 组 时才启用。有关详细信息,请参阅 --feature-gates--runtime-config kube-apiserver 参数。kube-scheduler、kube-controller-manager 和 kubelet 也需要该功能门控。

快速检查 Kubernetes 集群是否支持该功能的方法是列出 ResourceClass 对象:

kubectl get resourceclasses

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

No resources found

如果不支持,则会打印此错误:

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

仅当启用了功能门控并且使用 v1 配置 API 时,kube-scheduler 的默认配置才会启用“DynamicResources”插件。自定义配置可能需要修改才能包含它。

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

下一步

上次修改时间:2024 年 5 月 1 日下午 5:33 PST:更新 dynamic-resource-allocation.md (8cf5f3afe2)