动态资源分配
Kubernetes v1.32 [beta]
(enabled by default: false)Kubernetes v1.26 [alpha]
(enabled by default: false)动态资源分配是一个用于在 Pod 之间和 Pod 内部容器之间请求和共享资源的 API。 它是持久卷 API 针对一般资源的泛化。通常这些资源是 GPU 这类设备。
第三方资源驱动程序负责跟踪和准备资源, Kubernetes 通过结构化参数(在 Kubernetes 1.30 中引入)处理资源的分配。 不同类别的资源支持任意参数来定义要求和初始化。
Kubernetes v1.26 至 1.31 包含了经典 DRA 的(Alpha)实现,该实现已不再支持。 本文档适用于 Kubernetes v1.32,解释了 Kubernetes 中当前的动态资源分配方法。
准备开始
Kubernetes v1.32 包含用于动态资源分配的集群级 API 支持, 但它需要被显式启用。 你还必须为此 API 要管理的特定资源安装资源驱动程序。 如果你未运行 Kubernetes v1.32, 请查看对应版本的 Kubernetes 文档。
API
resource.k8s.io/v1beta1
API 组
提供了以下类型:
- ResourceClaim
- 描述对集群中资源的访问请求,工作负载需要使用这些资源。 例如,如果工作负载需要具有特定属性的加速器设备,就可以通过这种方式表达该请求。 状态部分跟踪此请求是否已被满足以及具体已分配了哪些资源。
- ResourceClaimTemplate
- 定义用于创建 ResourceClaim 的规约和一些元数据。 部署工作负载时由用户创建。 每个 Pod 的 ResourceClaim 随后会被 Kubernetes 自动创建和移除。
- DeviceClass
- 包含某些设备的预定义选择标准和配置。 DeviceClass 由集群管理员在安装资源驱动程序时创建。 对 ResourceClaim 中某个设备的每个分配请求都必须准确引用一个 DeviceClass。
- ResourceSlice
- 用于 DRA 驱动程序发布关于集群中可用资源的信息。
所有选择设备的参数都在 ResourceClaim 和 DeviceClass 中使用内置类型定义。 其中可以嵌入配置参数。哪些配置参数有效取决于 DRA 驱动程序 —— Kubernetes 只是将它们传递下去而不进行解释。
core/v1
的 PodSpec
在 resourceClaims
字段中定义 Pod 所需的 ResourceClaim。
该列表中的条目引用 ResourceClaim 或 ResourceClaimTemplate。
当引用 ResourceClaim 时,使用此 PodSpec 的所有 Pod
(例如 Deployment 或 StatefulSet 中的 Pod)共享相同的 ResourceClaim 实例。
引用 ResourceClaimTemplate 时,每个 Pod 都有自己的实例。
容器资源的 resources.claims
列表定义容器可以访问的资源实例,
从而可以实现在一个或多个容器之间共享资源。
下面是一个虚构的资源驱动程序的示例。 该示例将为此 Pod 创建两个 ResourceClaim 对象,每个容器都可以访问其中一个。
apiVersion: resource.k8s.io/v1beta1
kind: DeviceClass
name: resource.example.com
spec:
selectors:
- cel:
expression: device.driver == "resource-driver.example.com"
---
apiVersion: resource.k8s.io/v1beta1
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
调度
使用结构化参数
调度器负责在 Pod 需要资源时为 ResourceClaim 分配资源。 通过从 ResourceSlice 对象中检索可用资源的完整列表, 跟踪已分配给现有 ResourceClaim 的资源,然后从剩余的资源中进行选择。
目前唯一支持的资源类别是设备。 设备实例具有名称以及多个属性和容量信息。 设备通过 CEL 表达式被选择,这些表达式检查设备的属性和容量。 此外,所选择的设备集合还可以限制为满足特定约束的集合。
所选资源与所有供应商特定配置一起被记录在 ResourceClaim 状态中, 因此当 Pod 即将在节点上启动时,节点上的资源驱动程序具有准备资源所需的所有信息。
通过使用结构化参数,调度器能够在不与 DRA 资源驱动程序通信的情况下做出决策。 它还能够通过将 ResourceClaim 分配信息保存在内存中,并在同时将 Pod 绑定到节点的同时将此信息写入 ResourceClaim 对象中,快速调度多个 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]
(enabled by default: false)你可以在 ResourceClaim 或 ResourceClaimTemplate 中标记一个请求为具有特权特性。 具有管理员访问权限的请求可以允许用户访问使用中的设备,并且在将设备提供给容器时可能授权一些额外的访问权限:
apiVersion: resource.k8s.io/v1beta1
kind: ResourceClaimTemplate
metadata:
name: large-black-cat-claim-template
spec:
spec:
devices:
requests:
- name: req-0
deviceClassName: resource.example.com
adminAccess: true
如果此特性被禁用,创建此类 ResourceClaim 时将自动移除 adminAccess
字段。
管理性质访问是一种特权模式,在多租户集群中不应该对普通用户开放。 集群管理员可以通过安装类似于以下示例的验证准入策略来限制哪些负载能够使用此特性。 集群管理员至少需要调整 name 属性并将 "dra.example.com" 替换为有意义的值。
# 仅将管理性质访问权限授予具有 "admin-access.dra.example.com" 标签的命名空间。
# 也可以采用其他方式做出此类决定。
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: resourceclaim-policy.dra.example.com
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["resource.k8s.io"]
apiVersions: ["v1alpha3", "v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["resourceclaims"]
validations:
- expression: '! object.spec.devices.requests.exists(e, has(e.adminAccess) && e.adminAccess)'
reason: Forbidden
messageExpression: '"admin access to devices not enabled"'
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: resourceclaim-binding.dra.example.com
spec:
policyName: resourceclaim-policy.dra.example.com
validationActions: [Deny]
matchResources:
namespaceSelector:
matchExpressions:
- key: admin-access.dra.example.com
operator: DoesNotExist
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: resourceclaimtemplate-policy.dra.example.com
spec:
failurePolicy: Fail
matchConstraints:
resourceRules:
- apiGroups: ["resource.k8s.io"]
apiVersions: ["v1alpha3", "v1beta1"]
operations: ["CREATE", "UPDATE"]
resources: ["resourceclaimtemplates"]
validations:
- expression: '! object.spec.spec.devices.requests.exists(e, has(e.adminAccess) && e.adminAccess)'
reason: Forbidden
messageExpression: '"admin access to devices not enabled"'
---
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicyBinding
metadata:
name: resourceclaimtemplate-binding.dra.example.com
spec:
policyName: resourceclaimtemplate-policy.dra.example.com
validationActions: [Deny]
matchResources:
namespaceSelector:
matchExpressions:
- key: admin-access.dra.example.com
operator: DoesNotExist
ResourceClaim 设备状态 {#resourceclaim-device-status}
Kubernetes v1.32 [alpha]
(enabled by default: false)驱动程序可以报告资源申领中各个已分配设备的、特定于驱动程序的设备状态。 例如,可以在 ResourceClaim 状态中报告分配给网络接口设备的 IP。
驱动程序设置状态,信息的准确性取决于 DRA 驱动程序的具体实现。因此,所报告的设备状态可能并不总是反映设备状态的实时变化。
当此特性被禁用时,该字段会在存储 ResourceClaim 时自动清除。
针对一个已经设置了 status.devices
字段的现有 ResourceClaim 而言,如果 DRA
驱动能够更新该 ResourceClaim,则有可能支持 ResourceClaim 设备状态这一特性。
启用动态资源分配
动态资源分配是一个 Beta 特性,默认关闭,只有在启用 DynamicResourceAllocation
特性门控
和 resource.k8s.io/v1beta1
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
特性门控时才生效。
接下来
- 了解更多该设计的信息, 参阅使用结构化参数的动态资源分配 KEP。