动态资源分配
Kubernetes v1.32 [beta]
(默认禁用: false)动态资源分配是用于在 Pod 内的 Pod 和容器之间请求和共享资源的 API。它是持久卷 API 在通用资源方面的泛化。典型地,这些资源是像 GPU 这样的设备。
第三方资源驱动负责跟踪和准备资源,资源的分配由 Kubernetes 通过*结构化参数*(在 Kubernetes 1.30 中引入)处理。不同类型的资源支持任意参数来定义需求和初始化。
Kubernetes v1.26 至 1.31 包含了一个*经典 DRA* 的(alpha)实现,该实现已不再受支持。这份文档适用于 Kubernetes v1.33,解释了 Kubernetes 中动态资源分配的当前方法。
开始之前
Kubernetes v1.33 包含动态资源分配的集群级别 API 支持,但它需要被显式启用。你也必须为你打算使用此 API 管理的特定资源安装一个资源驱动。如果你运行的不是 Kubernetes v1.33,请查看该版本的 Kubernetes 文档。
API
resource.k8s.io/v1beta1
和 resource.k8s.io/v1beta2
API 组提供了这些类型
- ResourceClaim
- 描述工作负载访问集群中资源的请求。例如,如果工作负载需要具有特定属性的加速设备,这就是表达该请求的方式。status 字段跟踪此声明是否已满足以及分配了哪些特定资源。
- ResourceClaimTemplate
- 定义用于创建 ResourceClaim 的 spec 和一些元数据。由用户在部署工作负载时创建。然后,Kubernetes 会自动为每个 Pod 创建和删除 ResourceClaim。
- DeviceClass
- 包含某些设备的预定义选择标准及其配置。DeviceClass 由集群管理员在安装资源驱动时创建。ResourceClaim 中分配设备的每个请求都必须引用恰好一个 DeviceClass。
- ResourceSlice
- 由 DRA 驱动用于发布集群中可用资源(通常是设备)的信息。
- DeviceTaintRule
- 由管理员或控制平面组件用于向 ResourceSlice 中描述的设备添加设备污点。
选择设备的所有参数都在 ResourceClaim 和 DeviceClass 中使用树内类型定义。配置参数可以嵌入其中。哪些配置参数有效取决于 DRA 驱动 -- Kubernetes 仅传递它们而不进行解释。
core/v1
PodSpec
在 resourceClaims
字段中定义了 Pod 所需的 ResourceClaim。该列表中的条目引用 ResourceClaim 或 ResourceClaimTemplate。当引用 ResourceClaim 时,所有使用此 PodSpec 的 Pod(例如,在 Deployment 或 StatefulSet 内)共享同一个 ResourceClaim 实例。当引用 ResourceClaimTemplate 时,每个 Pod 都会获得自己的实例。
容器资源的 resources.claims
列表定义了容器是否获得对这些资源实例的访问权,这使得在一个或多个容器之间共享资源成为可能。
这是一个虚构资源驱动的示例。将为此 Pod 创建两个 ResourceClaim 对象,每个容器都可以访问其中一个。
apiVersion: resource.k8s.io/v1beta2
kind: DeviceClass
metadata:
name: resource.example.com
spec:
selectors:
- cel:
expression: device.driver == "resource-driver.example.com"
---
apiVersion: resource.k8s.io/v1beta2
kind: ResourceClaimTemplate
metadata:
name: large-black-cat-claim-template
spec:
spec:
devices:
requests:
- name: req-0
exactly:
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
调度
当 Pod 需要资源时,调度器负责将资源分配给 ResourceClaim。它通过从 ResourceSlice 对象中检索可用资源的完整列表,跟踪哪些资源已被分配给现有 ResourceClaim,然后从剩余的资源中进行选择来实现这一点。
目前唯一受支持的资源类型是设备。一个设备实例有一个名称和多个属性和容量。设备通过检查这些属性和容量的 CEL 表达式进行选择。此外,所选设备集合也可以被限制为满足某些约束的集合。
选择的资源与任何特定于供应商的配置一起记录在 ResourceClaim status 中,因此当 Pod 即将在节点上启动时,节点上的资源驱动拥有准备资源所需的所有信息。
通过使用结构化参数,调度器无需与任何 DRA 资源驱动通信即可做出决策。它还可以通过在内存中保留 ResourceClaim 分配信息并在后台将此信息写入 ResourceClaim 对象,同时将 Pod 绑定到节点,从而快速调度多个 Pod。
监控资源
Kubelet 提供一个 gRPC 服务,用于发现正在运行的 Pod 的动态资源。有关 gRPC 端点的更多信息,请参阅资源分配报告。
预调度 Pod
当你(或其他 API 客户端)创建一个已设置 spec.nodeName
的 Pod 时,调度器会被绕过。如果该 Pod 所需的某些 ResourceClaim 尚不存在、未分配或未为该 Pod 保留,则 Kubelet 将无法运行该 Pod 并周期性地重新检查,因为这些要求可能稍后仍会满足。
当 Pod 被调度时,如果调度器中未启用动态资源分配支持(例如,版本差异、配置、特性门控等),也可能出现这种情况。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
字段并改用节点选择器。
管理员访问
Kubernetes v1.32 [alpha]
(默认禁用: false)你可以在 ResourceClaim 或 ResourceClaimTemplate 中的请求中标记其具有用于维护和故障排除任务的特权功能。具有管理员访问权限的请求授予对正在使用设备的访问权,并在容器中提供设备时可以启用额外的权限。
apiVersion: resource.k8s.io/v1beta2
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
字段。这确保了非管理员用户无法滥用此特性。
ResourceClaim 设备状态
Kubernetes v1.33 [beta]
(默认启用: true)驱动程序可以报告资源声明中每个已分配设备的驱动程序特定设备状态数据。例如,分配给网络接口设备的 IP 可以在 ResourceClaim status 中报告。
由设置状态的驱动程序决定,信息的准确性取决于这些 DRA 驱动程序的实现。因此,报告的设备状态可能不总是反映设备状态的实时变化。
当此特性被禁用时,在存储 ResourceClaim 时会自动清除该字段。
当 DRA 驱动程序可以更新已设置 status.devices
字段的现有 ResourceClaim 时,ResourceClaim 设备状态受到支持。
优先列表
Kubernetes v1.33 [alpha]
(默认禁用: false)你可以在 ResourceClaim 的请求中提供子请求的优先列表。调度器将选择第一个可以分配的子请求。这允许用户在首选设备不可用时指定工作负载可以使用的备选设备。
在下面的示例中,ResourceClaimTemplate 请求了一个颜色为黑色、尺寸为大的设备。如果具有这些属性的设备不可用,Pod 将无法被调度。通过优先列表特性,可以指定第二个备选方案,该方案请求两个颜色为白色、尺寸为小的设备。如果大的黑色设备可用,它将被分配。但如果它不可用,并且有两个小的白色设备可用,Pod 仍然可以运行。
apiVersion: resource.k8s.io/v1beta2
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
可分区设备
Kubernetes v1.33 [alpha]
(默认禁用: false)DRA 中表示的设备不一定必须是连接到单台机器的单个单元,也可以是由连接到多台机器的多个设备组成的逻辑设备。这些设备可能会消耗底层物理设备的重叠资源,这意味着当一个逻辑设备被分配时,其他设备将不再可用。
在 ResourceSlice API 中,这表示为一个命名 CounterSet 列表,每个 CounterSet 都包含一组命名计数器。这些计数器表示物理设备上可用的、由通过 DRA 公告的逻辑设备使用的资源。
逻辑设备可以指定 ConsumesCounters 列表。每个条目包含对一个 CounterSet 的引用以及一组带有它们将消耗的数量的命名计数器。因此,设备要可分配,引用的 CounterSet 必须具有设备引用的计数器所需的足够数量。
这是一个两个设备的示例,每个设备从一个共享的、具有 8Gi 内存的计数器消耗 6Gi 内存。因此,在任何时间点只能分配其中一个设备。调度器会处理这种情况,这对消费者是透明的,因为 ResourceClaim API 不受影响。
kind: ResourceSlice
apiVersion: resource.k8s.io/v1beta2
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
设备污点和容忍度
Kubernetes v1.33 [alpha]
(默认禁用: false)设备污点类似于节点污点:污点具有字符串键、字符串值和效果。该效果应用于使用受污染设备的 ResourceClaim 以及所有引用该 ResourceClaim 的 Pod。“NoSchedule” 效果会阻止调度这些 Pod。在尝试分配 ResourceClaim 时,受污染的设备会被忽略,因为使用它们会阻止 Pod 的调度。
“NoExecute” 效果包含“NoSchedule”,此外还会导致所有已调度 Pod 被逐出。这种逐出由 kube-controller-manager 中的设备污点逐出控制器通过删除受影响的 Pod 实现。
ResourceClaim 可以容忍污点。如果污点被容忍,其效果不适用。空的容忍度匹配所有污点。容忍度可以限制为某些效果和/或匹配某些键/值对。容忍度可以检查某个键是否存在(无论其值如何),也可以检查特定键的特定值。有关此匹配的更多信息,请参阅节点污点概念。
通过在特定持续时间内容忍污点,可以延迟逐出。延迟开始于污点被添加到设备的时间,该时间记录在污点的一个字段中。
如上所述,污点也适用于分配节点上“所有”设备的 ResourceClaim。所有设备必须未被污染,或者所有污点都必须被容忍。分配具有管理员访问权限的设备(如上所述)也不例外。使用该模式的管理员必须显式容忍所有污点才能访问受污染的设备。
可以通过两种不同的方式将污点添加到设备
驱动设置的污点
DRA 驱动程序可以将其在 ResourceSlice 中发布的设备信息中添加污点。请查阅 DRA 驱动程序的文档,了解该驱动程序是否使用污点及其键和值是什么。
管理员设置的污点
管理员或控制平面组件可以对设备添加污点,而无需告知 DRA 驱动程序在其 ResourceSlice 中的设备信息中包含污点。他们通过创建 DeviceTaintRule 来实现。每个 DeviceTaintRule 为与设备选择器匹配的设备添加一个污点。如果没有这样的选择器,则不会对任何设备添加污点。这使得意外遗漏选择器而逐出所有使用 ResourceClaim 的 Pod 的可能性降低。
可以通过提供 DeviceClass、驱动程序、池和/或设备的名称来选择设备。DeviceClass 选择该 DeviceClass 中选择器所选择的所有设备。仅通过驱动程序名称,管理员就可以对该驱动程序管理的所有设备添加污点,例如在整个集群中对该驱动程序进行某种维护时。如果驱动程序管理节点本地设备,添加池名称可以将污点限制在单个节点上。
最后,添加设备名称可以选择一个特定的设备。如果需要,设备名称和池名称也可以单独使用。例如,建议节点本地设备的驱动程序使用节点名称作为其池名称。然后,使用该池名称添加污点会自动对节点上的所有设备添加污点。
驱动程序可能使用像“gpu-0”这样的稳定名称,这些名称隐藏了当前分配给该名称的特定设备。为了支持对特定硬件实例添加污点,如果驱动程序为其硬件支持供应商特定的唯一 ID 属性,则可以在 DeviceTaintRule 中使用 CEL 选择器来匹配该属性。
污点在 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
启用动态资源分配
动态资源分配是一个* Beta 特性*,默认关闭,只有当 DynamicResourceAllocation
特性门控以及 resource.k8s.io/v1beta1
和 resource.k8s.io/v1beta2
API 组被启用时才开启。有关详细信息,请参阅 --feature-gates
和 --runtime-config
kube-apiserver 参数。kube-scheduler、kube-controller-manager 和 kubelet 也需要该特性门控。
当资源驱动程序报告设备状态时,除了 DynamicResourceAllocation
之外,还必须启用 DRAResourceClaimDeviceStatus
特性门控。
快速检查 Kubernetes 集群是否支持该特性可以通过列出 DeviceClass 对象来完成,使用命令
kubectl get deviceclasses
如果你的集群支持动态资源分配,响应将是 DeviceClass 对象列表或
No resources found
如果不支持,则打印此错误
error: the server doesn't have a resource type "deviceclasses"
kube-scheduler 的默认配置仅在特性门控启用且使用 v1 配置 API 时才启用“DynamicResources”插件。自定义配置可能需要修改以包含它。
除了在集群中启用此特性之外,还必须安装资源驱动程序。详细信息请参阅驱动程序的文档。
启用管理员访问
管理员访问是一个* Alpha 特性*,仅当在 kube-apiserver 和 kube-scheduler 中启用 DRAAdminAccess
特性门控时才会启用。
启用设备状态
ResourceClaim 设备状态是一个* Alpha 特性*,仅当在 kube-apiserver 中启用 DRAResourceClaimDeviceStatus
特性门控时才会启用。
启用优先列表
优先列表) 是一个* Alpha 特性*,仅当在 kube-apiserver 和 kube-scheduler 中启用 DRAPrioritizedList
特性门控时才会启用。它还需要启用 DynamicResourceAllocation
特性门控。
启用可分区设备
可分区设备是一个* Alpha 特性*,仅当在 kube-apiserver 和 kube-scheduler 中启用 DRAPartitionableDevices
特性门控时才会启用。
启用设备污点和容忍度
设备污点和容忍度是一个* Alpha 特性*,仅当在 kube-apiserver、kube-controller-manager 和 kube-scheduler 中启用 DRADeviceTaints
特性门控时才会启用。要使用 DeviceTaintRule,必须启用 resource.k8s.io/v1alpha3
API 版本。
下一步
- 有关设计的更多信息,请参阅使用结构化参数的动态资源分配 KEP。