kubernetes 1.32 DRA 原理解析
我们通过 KEP 来了解 DRA 的最新工作原理。
原文:
概述
新版本架构图
核心设计了四个 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 插件的两个方法 NodeUnprepareResources
和 NodePrepareResources
。
如果这是节点上使用特定资源实例的最后一个 Pod,则必须在允许删除 Pod 之前成功调用 NodeUnprepareResource
(见下文)。这确保了网络连接资源再次可用于其他 Pod,包括那些可能被调度到其他节点的 Pod。它还指示解除分配和删除 ResourceClaim 是安全的。
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;
}