Skip to main content

kubernetes 1.32 DRA 原理解析

· 8 min read
Softwore Developer

我们通过 KEP 来了解 DRA 的最新工作原理。

原文:

kubernetes 1.32 DRA 原理解析

概述

新版本架构图

image.png

核心设计了四个 CRD:

  • DeviceClass:这是一个供应商提供的 device class,类似于 StorageClass。
  • ResourceSlice: 主要记录节点上可用的设备
  • ResourceClaim:定义需要多少设备以及它们必须具备哪些功能
  • ResourceClaimTemplate: 创建ResourceClaim的模版定义

kube-controller-manager 中的新控制器可根据 ResourceClaimTemplates 创建 ResourceClaims,当 ResourceClaim 不再保留时,它会清除分配,从而使底层资源再次可用。

kube-scheduler 插件需要检测 Pod 的引用 ResourceClaim(直接或通过 ResourceClaimTemplates ),并确保在 Pod 调度之前分配资源。

DRA 驱动程序需要有如下功能:

  • admission webhook(可选):一个中心组件,用于在创建 ResourceClaims、ResourceClaimTemplates 和 DeviceClasses 时检查其中的不透明配置参数。如果没有它,则只能在 Pod 即将在节点上运行时检测到无效参数。
  • kubelet插件(必选):发布设备信息,与kubelet配合准备节点上设备的使用。

下面我们来看下 **resource.k8s.io** 这个资源组中定义的几个 CRD。

ResourceSlice

对于每个节点,都会创建一个或多个 ResourceSlice 对象。节点上的驱动程序会以节点为所有者发布这些对象,因此当节点发生故障时,这些对象会被删除,然后被移除。

所有列表类型都是原子的,因为这样可以更轻松地跟踪服务器端应用 (SSA) 的所有者。无需修补单个列表元素,并且只有一个所有者。

type ResourceSliceSpec struct {
// 驱动程序名字
Driver string
// Pool 描述的是此 ResourceSlice 所属的池。
Pool ResourcePool
// NodeName 标识在此池中提供资源的节点。
NodeName string
// NodeSelector 定义哪些节点可以访问这个资源池
NodeSelector *core.NodeSelector
// 表示所有节点都可以访问Pool中的资源,这个感觉是给网络设备使用的
AllNodes bool
// 定义节点上的所有device
Devices []Device
}

// ResourcePool describes the pool that ResourceSlices belong to.
type ResourcePool struct {
// pool的唯一名字,在节点级别通常是节点name
Name string
// 没懂这个字段
Generation int64

// ResourceSliceCount 是此 Generation 时池中的 ResourceSlice 总数
ResourceSliceCount int64
}

ResourceClaim

  • scheduler 程序必须在 ResourceClaim 中设置终结器 Finalizer = "resource.kubernetes.io/delete-protection",然后才能添加分配。
type DeviceClaim struct {
// 请求代表对不同设备的单独请求,这些请求必须全部满足。如果为空,则无需分配任何内容。
Requests []DeviceRequest
// 分配给声明的设备集必须满足这些约束。
Constraints []DeviceConstraint
// 此字段保存可满足此声明中的请求的多个潜在驱动程序的配置。
Config []DeviceClaimConfiguration

// Score *SomeScoringStruct
}
type DeviceRequest struct {
// pod.spec.containers[].resources.claims 的引用名称
Name string
// DeviceClass
DeviceClassName string
// 选择器定义特定设备必须满足的条件
Selectors []DeviceSelector
// AllocationMode 分配模式
// - ExactCount: 此请求针对特定数量的设备。这是默认值。确切数量在计数字段中提供。
// - All: 此请求针对池中的所有匹配设备。如果某些设备已分配,则分配将失败,除非请求 adminAccess。
AllocationMode DeviceAllocationMode
// 当模式是ExactCount,需要指定请求的数量; 默认值是1
Count int64
// AdminAccess 表示这是对设备的管理访问权的声明
AdminAccess bool
}
type DeviceSelector struct {
// CEL 包含用于选择设备的 CEL 表达式。
CEL *CELDeviceSelector
}
type ResourceClaimStatus struct {
// 一旦claim被成功分配,就会设置分配。
Allocation *AllocationResult

// ReservedFor 表示当前允许使用声明的实体
ReservedFor []ResourceClaimConsumerReference
}

DeviceClass

type DeviceClassSpec struct {
// 每个选择器都必须由通过此类声明的设备来满足。
Selectors []DeviceSelector
// Config 定义适用于通过此类声明的每个设备的配置参数。
Config []DeviceClassConfiguration
}

ResourceClaimTemplate


// ResourceClaimTemplateSpec 包含 ResourceClaim 的元数据和字段。
type ResourceClaimTemplateSpec struct {
metav1.ObjectMeta
// ResourceClaimSpec
Spec ResourceClaimSpec
}

管理资源

kubelet 必须确保在运行使用特定资源实例的第一个 Pod 之前,资源在节点上可用,并在最后一个使用该资源的 Pod 终止后,使资源在其他地方再次可用。对于这两个操作,kubelet 都会调用 kubelet 插件的两个方法 NodeUnprepareResourcesNodePrepareResources

如果这是节点上使用特定资源实例的最后一个 Pod,则必须在允许删除 Pod 之前成功调用 NodeUnprepareResource(见下文)。这确保了网络连接资源再次可用于其他 Pod,包括那些可能被调度到其他节点的 Pod。它还指示解除分配和删除 ResourceClaim 是安全的。

image.png

NodePrepareResource

当想要使用指定资源的 Pod 被调度到节点上时,kubelet 会调用此 RPC。插件应假定此 RPC 将在将使用资源的节点上执行。

插件应确保分配的资源有 CDI 格式的 json 文件。在创建使用该资源的容器之前,运行时应使用这些文件来更新运行时配置。

message NodePrepareResourcesRequest {
// 需要准备的 ResourceClaims 列表。
repeated Claim claims = 1;
}

message NodePrepareResourcesResponse {
// 已完成准备的 ResourceClaims
map<string, NodePrepareResourceResponse> claims = 1;
}

message NodePrepareResourceResponse {
// 设备列表
repeated Device devices = 1;
// 错误信息
string error = 2;
}
message Device {
// 声明中与此设备关联的请求。
repeated string request_names = 1;
// 包含设备的池
string pool_name = 2;
// 设备本身
string device_name = 3;
// 单个设备实例可能映射到多个 CDI 设备 ID。
repeated string cdi_device_ids = 4 [(gogoproto.customname) = "CDIDeviceIDs"];
}

此处的request_names允许 kubelet 为使用特定请求中的设备而不是声明的所有设备的容器找到正确的 CDI ID。

NodeUnprepareResources

Kubelet 插件必须实现此 RPC 调用。此 RPC 是 NodePrepareResource 的反向操作。此 RPC 必须撤消相应 NodePrepareResource 的工作。对于每个成功的 NodePrepareResource,kubelet 至少应调用一次此 RPC。插件应假定此 RPC 将在使用资源的节点上执行。

message NodeUnprepareResourcesRequest {
// 需要释放的 ResourceClaims 列表。
repeated Claim claims = 1;
}
message NodeUnprepareResourcesResponse {
// 已撤销准备的 ResourceClaims。
map<string, NodeUnprepareResourceResponse> claims = 1;
}
message NodeUnprepareResourceResponse {
// 如果有错误
string error = 1;
}

参考:https://github.com/kubernetes/enhancements/tree/master/keps/sig-node/4381-dra-structured-parameters#design-details