这是本节的多页打印视图。
点击此处打印.
返回本页常规视图.
Workload API
特性状态:
Beta since Kubernetes v1.37; (默认禁用)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
Workload API 资源允许你描述一个多 Pod 应用的调度需求和结构。
虽然工作负载控制器提供了运行时行为,但 Workload API 旨在为“真实”的工作负载(例如 Job 等)提供调度约束。
什么是 Workload?
Workload API 资源属于 scheduling.k8s.io/v1alpha1
API 组
(在使用此 API 之前,你的集群必须启用该 API 组以及 GenericWorkload
特性门控)。
此资源作为一种结构化、机器可读的定义,用于描述多 Pod 应用的调度需求。
面向用户的工作负载(例如 Job)定义“运行什么”,
而 Workload 资源则决定一组 Pod 应该如何被调度,以及在其整个生命周期中如何管理其调度位置。
API 结构
Workload 允许你定义一组 Pod,并为其应用调度策略。
Workload 由两个部分组成:Pod 分组列表和到某个控制器的引用。
PodGroupTemplates
spec.podGroupTemplates 列表定义了你的工作负载的不同组件。
例如,一个机器学习作业可能有一个 driver 模板和一个 worker 模板。
podGroupTemplates 中的每个条目必须包含:
- 一个唯一的
name,用于在 PodGroup 的 spec.podGroupTemplateRef 中引用此模板。 - 一个调度策略(
basic 或 gang)。
如果启用了 WorkloadAwarePreemption
特性门控,
则 podGroups 中的每个条目也可以有优先级和干扰模式。
单个工作负载中 PodGroupTemplates 的最大数量为 8。
apiVersion: scheduling.k8s.io/v1alpha2
kind: Workload
metadata:
name: training-job-workload
namespace: some-ns
spec:
controllerRef:
apiGroup: batch
kind: Job
name: training-job
podGroupTemplates:
- name: workers
schedulingPolicy:
gang:
# 只有当 4 个 Pod 可以同时运行时,该进程才能被调度。
minCount: 4
priorityClassName: high-priority # 仅适用于启用 WorkloadAwarePreemption 特性门控的情况
disruptionMode: PodGroup # 仅适用于启用 WorkloadAwarePreemption 特性门控的情况
当工作负载控制器根据这些模板之一创建 PodGroup 时,
它会将 schedulingPolicy 复制到 PodGroup 自身的规范中。
对 Workload 的更改只会影响新创建的 PodGroup,而不会影响已存在的 PodGroup。
引用工作负载控制对象
controllerRef 字段用于将 Workload 关联回定义此应用的具体高层对象,
例如 Job 或定制 CRD。
这对于可观测性和工具链非常有用。此数据不会用于 Workload 的调度或管理。
使用 Job 进行 Gang 调度
特性状态:
Alpha since Kubernetes v1.36; (默认禁用)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the WorkloadWithJob feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
当启用了 WorkloadWithJob
特性门控时,Job
控制器会自动为并行索引 Job 创建 Workload 和 PodGroup 对象,
其中 .spec.parallelism 等于 .spec.completions。
Gang 策略的 minCount 被设置为 Job 的并行度,因此所有 Pod 必须能够一起调度,
然后它们中的任何一个才能绑定到节点。
这是使用 Job 进行 Gang 调度的内置路径。你不需要自己创建 Workload 或 PodGroup 对象,因为 Job 控制器会自动处理。
其他工作负载控制器(如 JobSet)可能会独立管理自己的 Workload 和 PodGroup 对象。
接下来
1 - Pod 组干扰和优先级
Kubernetes no longer includes this feature / behavior. The last release of Kubernetes that recognized the WorkloadAwarePreemption feature gate was 1.36. You can no longer toggle that setting.
PodGroup 可以声明一个干扰模式。此模式规定了调度器如何干扰运行中的 PodGroup,
例如为了容纳更高优先级的 PodGroup。PodGroup 还具有优先级,
该优先级会在工作负载感知抢占
事件中覆盖来自该组的单个 Pod 的优先级。
干扰模式类型
说明:
截至 1.36 版本,PodGroup 的 priority 或 disruptionMode
字段仅被工作负载感知抢占所尊重。
在 Pod 调度阶段,调度器不考虑 PodGroup 的 priority 或 disruptionMode 字段。
API 支持两种干扰模式:Pod 和 PodGroup。默认模式是 Pod。
Pod
Pod 模式指示调度器将组中的所有 Pod 视为单独的实体,
允许从 PodGroup 中独立干扰单个 Pod。
PodGroup
PodGroup 模式强调干扰的 "全有或全无" 语义。
它指示调度器必须同时干扰 PodGroup 中的所有 Pod。
Pod 组优先级
PodGroup 使用与单个 Pod 相同的 PriorityClass 概念。
创建一个或多个 PriorityClass 后,你可以创建一个 PodGroup,
并在其规约中指定这些 PriorityClass 名称之一。
优先级准入控制器使用 priorityClassName 字段并填充优先级的整数值。
如果未找到优先级类,则 PodGroup 会被拒绝。
当 PodGroup 未设置 priorityClassName 时,Kubernetes 会寻找默认值(globalDefault 设置为 true 的 PriorityClass)。
如果没有 globalDefault 设置为 true 的 PriorityClass,
则没有 priorityClassName 的 PodGroup 优先级为零。
PodGroup 的优先级是该组中所有 Pod 在
工作负载感知抢占
事件中的权威优先级,
即使组成该 PodGroup 的各个 Pod 的优先级不同也是如此。
以下 YAML 是使用 high-priority PriorityClass 的 PodGroup 配置示例,
该 PriorityClass 映射到整数值 1000000 的优先级。
优先级准入控制器检查规约并将 PodGroup 的优先级解析为 1000000。
apiVersion: scheduling.k8s.io/v1alpha2
kind: PodGroup
metadata:
namespace: ns-1
name: job-1
spec:
priorityClassName: high-priority
接下来
2 - PodGroup 调度策略
特性状态:
Beta since Kubernetes v1.37; (默认禁用)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
每个 PodGroup
都必须在其 spec.schedulingPolicy 字段中声明一个调度策略。
此策略决定了调度器如何处理组中的 Pod 集合。
策略类型
schedulingPolicy 字段支持两种策略类型:basic 和 gang。你必须指定其中一种。
Basic 策略
basic 策略指示调度器尽力评估所有 Pod。与 gang 策略不同,使用 basic
策略的 PodGroup 无论其当前有多少 Pod 可调度,都被认为是可行的。
使用 basic 策略的主要原因是将 Pod 组织成组,以提升可观测性和管理能力,
同时仍然在单个原子
PodGroup 调度周期内对它们进行一起评估。
此策略可用于那些不需要同时启动但逻辑上属于同一组的群体,
或者为不涉及“全有或全无”的组约束提供扩展空间。
schedulingPolicy:
basic: {}
Gang 策略
gang 策略强制执行“全有或全无”的调度机制。这对于紧密耦合的工作负载非常重要,因为部分启动可能导致死锁或资源浪费。
此策略常用于 Job
或其他需要所有 Worker 同时运行才能推进的批处理任务。
gang 策略需要一个 minCount 字段,该字段表示为了使该组可行,必须同时调度的最小 Pod 数量:
schedulingPolicy:
gang:
# 允许以组同时调度所需的最小 Pod 数量
minCount: 4
通过 PodGroupTemplates 设置策略
使用 Workload API 时,
你需要在 PodGroupTemplates 中定义调度策略。
工作负载控制器会将模板中的策略复制到它创建的每个 PodGroup 中,
从而使 PodGroup 成为自包含的。对工作负载模板的更改只会影响新创建的 PodGroup,
而不会影响已存在的 PodGroup。
对于独立 PodGroup(未通过工作负载创建),你可以直接在
PodGroup 本身上设置 spec.schedulingPolicy。
CompositePodGroup 中的策略
特性状态:
Alpha since Kubernetes v1.37; (默认禁用)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
当 CompositePodGroup
特性门控和 scheduling.k8s.io/v1alpha3 API 组启用时,
Workload 中的 CompositePodGroupTemplate 和 CompositePodGroup 对象也可以声明调度策略。
PodGroup 中的调度策略管理的是一组单个 Pod,而
CompositePodGroup 的调度策略管理的是其直接的子组
(可以是 CompositePodGroup 和 PodGroup 对象)。
CompositePodGroup 的策略类型
与 PodGroup 类似,CompositePodGroup 的 spec.schedulingPolicy 字段支持两种类型:
basic:CompositePodGroup 中的子组被独立评估和准入。gang:在子组之间强制执行多级"全有或全无"的调度机制。
只有当至少 minGroupCount 个子组可以同时被调度时,CompositePodGroup 才是可调度的。
schedulingPolicy:
gang:
# 允许复合组同时调度的最小子组数量
minGroupCount: 2
通过模板设置复合策略
使用 Workload API 时,
CompositePodGroup 的调度策略在 CompositePodGroupTemplate 中定义。
工作负载控制器会将模板中指定的 schedulingPolicy 复制到运行时创建的每个 CompositePodGroup 中。
与可以更新 minCount 的叶子 PodGroupTemplate 不同,
CompositePodGroupTemplate 中的 minGroupCount 是不可变的。
接下来
3 - 拓扑感知工作负载调度
特性状态:
Alpha since Kubernetes v1.36; (默认禁用)
拓扑感知调度(Topology-Aware Scheduling,TAS)是 Workload API 的一项特性,
用于优化 Pod 在集群中的调度方式。
TAS 确保同一个 PodGroup 中的所有 Pod 被一起调度在特定的拓扑域中,
例如同一个服务器机架或同一个可用区。这减少了 Pod 之间通信的延迟,
并防止工作负载在集群基础设施中发生碎片化分布。
拓扑感知调度与 gang 调度策略配合使用
当 TAS 应用于使用 gang 调度策略的 PodGroup 时,TAS 会一次性模拟整个 Pod 组的潜在分配。
TAS 保证在真正分配资源之前,至少指定数量的 minCount Pod 可以一起调度到同一个拓扑域中。
如果找不到可行的调度方案,则整个 PodGroup 成为不可调度。
这是推荐用于分布式 AI 和 ML 训练等工作负载的方法,
因为这类场景通常严格要求 Pod 之间具备较近的物理距离,以降低通信延迟。
如果向已经存在部分已调度 Pod 的 PodGroup 中新增 Pod(例如 Pod 被重新创建时),
调度器将强制所有新传入的 Pod 落在现有 Pod 当前所在的完全相同的拓扑域中。
如果该特定拓扑域没有足够容量来容纳新的 Pod,这些 Pod 将保持 Pending 状态
——即使这意味着当前已调度的 Pod 数量少于 minCount。
说明:
截至 v1.36,TAS 不会触发工作负载或 Pod 抢占。如果在不触发抢占的情况下无法找到可行的调度方案,
则 PodGroup 成为不可调度。
拓扑感知调度与 basic 调度策略配合使用
将 TAS 与 basic 调度策略一起使用时,可能会出现不一致的行为。调度器在进入 PodGroup 调度周期时,
可能只能观测到部分 Pod,因此可行性评估仅针对已观测到的 Pod,而不是整个 PodGroup。为了部分缓解这一限制,
你可以使用调度门控,以便在 PodGroup 中所有 Pod 都进入调度队列之前暂缓调度。
如果无法为整个 PodGroup 找到可行的调度方案,则可能只有部分 Pod 会被调度,
但这些已调度的 Pod 仍然保证满足调度约束。
如果向已经存在部分已调度 Pod 的 PodGroup 中新增 Pod,
调度器的行为将与 gang 策略相同——强制新 Pod 进入相同的拓扑域,
除非容量不足(在这种情况下,新 Pod 将保持 Pending 状态)。
API 配置:调度约束
每个 PodGroup(或 PodGroupTemplate)都可以选择性声明 schedulingConstraints 字段,有关该字段的细节参阅
PodGroup 调度算法。
如果在 PodGroupTemplate 中定义了约束,这些约束会复制到引用该模板的 PodGroup 中。
截至 Kubernetes v1.36,API 支持拓扑约束。
说明:
截至 Kubernetes v1.36,你只可以在每个 PodGroup 中指定一个拓扑约束。
拓扑约束
要为 PodGroup 定义拓扑约束,你需要设置一个 key,
它对应 Kubernetes 节点上的某个标签,用于表示目标拓扑域(例如机架或可用区)。
调度器会严格保证:同一个 PodGroup 中的所有 Pod 只能被调度到具有相同标签值的节点上。
下面是一个配置了拓扑约束的 PodGroup 示例:
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
name: example-podgroup
spec:
schedulingPolicy:
gang:
minCount: 4
schedulingConstraints:
topology:
- key: topology.example.com/rack
多级拓扑感知调度
特性状态:
Alpha since Kubernetes v1.37; (默认禁用)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the CompositePodGroup feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
复杂工作负载可能需要将其 Pod 共置于集群基础架构的不同层级。
例如,整个工作负载可能需要运行在单个可用区内,而该工作负载的不同部分可能需要严格共置于特定服务器机架上。
此类多层级共置需求可以通过 CompositePodGroup API 表达,并在组层级结构的不同层次上指定拓扑约束。
使用 CompositePodGroup API 需要启用
CompositePodGroup
特性门控和 scheduling.k8s.io/v1alpha3 {{< glossary_tooltip text="API 组" term_id="api-group" >}}。
多层级拓扑约束解析
CompositePodGroup 层级结构中的每个组都可以指定一个拓扑约束,确保该组的所有后代
Pod 都会在与该组约束相匹配的同一拓扑域中进行调度。
在分层调度过程中,
调度器以自顶向下的方式解析这些约束。具体而言,在对子组进行调度时所考虑的拓扑域,
会被限定在父组所假定的位置对应的拓扑域之内。
Kubernetes 并不对拓扑标签的物理层级结构施加任何严格的要求 —— 拓扑键是任意的节点标签。
不过,你从父组到子组指定拓扑约束的顺序,决定了调度器对拓扑域进行细分的顺序。
说明:
从 Kubernetes v1.37 起,你只能在每个 CompositePodGroup 中指定一个拓扑约束。
示例
下面的示例配置了一个 Workload,其中父级 CompositePodGroupTemplate
将整个工作负载约束到单个可用区(topology.example.com/zone),而两个子级 PodGroupTemplate
条目(workers 和 driver)将它们各自的 Pod 约束到该可用区内的服务器机架(topology.example.com/rack):
apiVersion: scheduling.k8s.io/v1alpha3
kind: Workload
metadata:
name: example-workload
spec:
compositePodGroupTemplates:
- name: root
schedulingPolicy:
gang:
minGroupCount: 2
schedulingConstraints:
topology:
- key: topology.example.com/zone
podGroupTemplates:
- name: workers
schedulingPolicy:
gang:
minCount: 8
schedulingConstraints:
topology:
- key: topology.example.com/rack
- name: driver
schedulingPolicy:
gang:
minCount: 1
schedulingConstraints:
topology:
- key: topology.example.com/rack
在创建 Workload 对象之后,对应的组对象将被创建,如下:
- 根级
CompositePodGroup,引用 root 模板。 - 两个子级
PodGroup 对象(workers 和 driver),各自将根级 CompositePodGroup 引用为其父组。
apiVersion: scheduling.k8s.io/v1alpha3
kind: CompositePodGroup
metadata:
name: workload-root
spec:
workloadRef:
workloadName: example-workload
templateName: root
schedulingPolicy:
gang:
minGroupCount: 2
schedulingConstraints:
topology:
- key: topology.example.com/zone
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
name: workload-workers
spec:
parentCompositePodGroupName: workload-root
workloadRef:
workloadName: example-workload
templateName: workers
schedulingPolicy:
gang:
minCount: 8
schedulingConstraints:
topology:
- key: topology.example.com/rack
---
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
name: workload-driver
spec:
parentCompositePodGroupName: workload-root
workloadRef:
workloadName: example-workload
templateName: driver
schedulingPolicy:
gang:
minCount: 1
schedulingConstraints:
topology:
- key: topology.example.com/rack
在调度过程中,调度器首先为 workload-root 选择一个可用区,然后按机架细分该可用区内的节点,
以找到 workload-workers 和 workload-driver 在所选可用区内的可行机架放置位置。
例如,考虑一个包含五个节点的集群,其标签如下:
| Node | topology.example.com/zone | topology.example.com/rack |
|---|
node-a | zone-1 | rack-1 |
node-b | zone-1 | rack-1 |
node-c | zone-1 | rack-2 |
node-d | zone-2 | rack-1 |
node-e | zone-2 | rack-3 |
在处理 workload-root 时,调度器会基于 topology.example.com/zone 拓扑键,在所有集群节点上评估候选放置位置:
| 评估的候选位置 | 候选位置内的节点 |
|---|
zone-1 | node-a, node-b, node-c |
zone-2 | node-d, node-e |
在处理 workload-root 时,调度器会基于 topology.example.com/zone 拓扑键,在所有集群节点上评估候选放置位置:
| 评估的候选位置 | 候选位置内的节点 | |
|---|
zone-1 | rack-1 | node-a, node-b |
zone-1 | rack-2 | node-c |
zone-2 | rack-1 | node-d |
zone-2 | rack-3 | node-e |
为同级 workload-driver PodGroup 生成的候选放置位置与为 workload-workers
生成的相同,因为这两个组都指定了相同的拓扑键(topology.example.com/rack)。
接下来
4 - 调度构建块 API 与 workloadbuilder 库
可重用的调度 API 原语,树内和树外工作负载控制器将其嵌入自己的 API 中, 以及将这些原语编译为 Workload、PodGroup 和 CompositePodGroup 对象的共享 workloadbuilder 库。
特性状态:
Beta since Kubernetes v1.37; (默认禁用)
More information about this feature
To use this feature, you (or a cluster administrator) will need to enable the GenericWorkload feature gate for all relevant components in your cluster.
See Enable Or Disable Feature Gates for more information.
工作负载感知调度在 scheduling.k8s.io
API 组下定义了一组可重用的 API 构建块。
控制器作者可以将这些原语嵌入自己的 API,以便用户能够以一致的模式在整个生态系统中表达调度意图
(Gang 调度、拓扑、干扰行为),而共享的 workloadbuilder 库则把这种意图编译为面向调度器的
Workload、
PodGroup 和
CompositePodGroup 对象。
目前这些构建块的内置使用方是
Job 控制器,它由 WorkloadWithJob
特性门控控制启用。
可重用的构建块
这些构建块是 scheduling.k8s.io/v1alpha3 API 组中强类型的 Go 结构体。
它们是面向控制器作者的:控制器将这些结构体作为字段嵌入自己的 API 类型,
再由 workloadbuilder 库进行编译。类型名称遵循两种约定:
叶子级类型的名称以 WorkloadPodGroup... 为前缀(例如
WorkloadPodGroupSchedulingPolicy),多级变体则以 WorkloadCompositePodGroup... 为前缀。
每个控制器都可以为自己的 API 选择惯用的字段名称和结构,因此这些构建块并不强制固定的顶层结构。
虽然并非硬性要求,但建议复用标准的字段名称和结构,这样在一个控制器的资源上配置过 Gang 调度的用户,
就能在另一个控制器的资源上认出相同的选项。
要采用这些构建块,控制器可以把想要支持的那些构建块作为字段添加到自己的类型上。
例如,Job API
把全部四种构建块归入一个可通过 spec.scheduling 访问的单一类型:
type JobSchedulingConfiguration struct {
SchedulingPolicy *schedulingv1alpha3.WorkloadPodGroupSchedulingPolicy
SchedulingConstraints *schedulingv1alpha3.WorkloadPodGroupSchedulingConstraints
DisruptionMode *schedulingv1alpha3.WorkloadPodGroupDisruptionMode
ResourceClaims []schedulingv1alpha3.WorkloadPodGroupResourceClaim
}
另一个控制器可能会按照多组件工作负载的各个组件来嵌套相同的构建块,
也可能只支持其中的一部分。
调度策略
调度策略构建块所包含的 basic 和 gang 策略与 PodGroup 的
spec.schedulingPolicy 相同。关于每种策略的含义以及调度器如何应用它们,
参见 PodGroup 调度策略。
唯一的区别是该构建块中 gang 的最小数量是可选的。
用户可以保持 minCount 未设置,此时控制器会提供一个适合自身领域的默认值;
例如,Job 控制器使用 Job 的并行度。
调度约束
调度约束构建块所包含的是拓扑感知工作负载调度中所述的拓扑约束:
一个用于指定域(例如机架或可用区)的节点标签键,
组内每个 Pod 都必须共享该域;每个组最多只能有一个拓扑约束。
控制器应在创建后冻结该字段,因为在编译后的 Workload 中约束是不可变的。
干扰模式
干扰模式构建块用于选择组内的 Pod 是可以被逐个干扰(single),
还是只能作为一个整体被干扰(all);这与
Pod 组干扰和优先级中所述的
Pod 和 PodGroup 两种干扰模式相对应。
该库会拒绝没有意义的组合。例如,对于使用 BasicSchedulingPolicy 的 PodGroup,
应阻止其使用 all 干扰模式,因为抢占单元不能大于调度单元 ——
以逐 Pod 方式调度的组没有组级别的单元可供抢占或干扰。
资源申领
资源申领构建块用于表达哪些动态资源分配申领由组内每个
Pod 共享,而不是按 Pod 分别分配。每个条目都在组内为该申领命名,并指向一个现有的
ResourceClaim 或
ResourceClaimTemplate,
申领由后者生成。一个组最多可以声明四个申领。
Pod 通过在自己的规约中声明一个匹配的申领来使用分配给该组的设备,使用相同的名称并引用同一个对象。
复合构建块
编排其他控制器的多级控制器(例如用 JobSet 创建 Job)需要协调组之组。
针对这一层,API 提供了一组类似的原语,名称以 WorkloadCompositePodGroup... 为前缀
(例如 WorkloadCompositePodGroupSchedulingPolicy)。它们的形态与叶子级构建块相同,
只是复合的 gang 策略使用 minGroupCount(必须能够一起调度的最小子组数)来代替叶子级的 minCount。
将叶子类型和复合类型区分开来,可以让每个层级独立演进。
示例:Job 集成
Job 控制器是这些构建块的内置使用示例。
用户填写 Job 的 spec.scheduling,控制器会将其编译为 Workload 和 PodGroup。
关于完整的 Job 清单、省略 spec.scheduling 时适用的默认值,以及创建后可更改哪些字段,
参见与 Workload API 集成。
workloadbuilder 库
workloadbuilder 是一个共享的 Go 库,它把控制器的调度意图转换为面向调度器的 Workload 及其运行时的
PodGroup/CompositePodGroup 对象,这样每个控制器都不必重新实现默认值填充、验证和模板编译。
它同时面向树内控制器(例如 Job 控制器)和树外控制器(例如 JobSet 或 Kubeflow TrainJob),
后者像引入其他任何 Go 依赖一样将它像供应商一样加进来。
该库位于 k8s.io/component-helpers/scheduling/schedulingv1/workloadbuilder。
该库使用 scheduling.k8s.io/v1alpha3 的构建块,
将它们编译为 scheduling.k8s.io/v1beta1 的 Workload 和 PodGroup 对象,
而 CompositePodGroup 对象仍为 scheduling.k8s.io/v1alpha3。
控制器如何使用该库
控制器将其工作负载描述为由 WorkloadItem 节点组成的树,每个逻辑组件对应一个节点。
没有子节点的节点会变成单个 PodGroupTemplate,
而有子节点的节点则会覆盖这些子节点而成为一个 CompositePodGroupTemplate,
多级控制器正是以此来表示组之组。每个节点都带有:
- 一份默认配置,即控制器针对用户未设置的所有内容所提供的自身默认值。
例如,控制器可以在这里决定,未配置的 Job 继续使用
basic 调度。 - 一份输入,即取自控制器 API 的用户意图。
控制器会记录每个构建块及其所在的字段路径,
因此验证错误会指向用户实际设置的那个准确字段。
- 可选的回调,用于调整合并后的配置。
控制器正是以此提供与上下文相关的默认值,
例如根据 Job 的并行度填充未设置的 gang 最小数量。
然后,控制器把这棵树交给一个 Builder,并依次执行四次调用:
NewBuilder 根据这棵树构造构建器,
同时指定要生成的对象的名称、名字空间和属主引用。
该属主会成为 Workload 的控制器引用,用于资源发现和垃圾回收。Validate 解析这棵树,并将任何问题以字段错误列表的形式报告出来,
控制器会从自己的 API 验证中返回这些错误。BuildWorkload 把这棵树编译为 Workload。
结果会被缓存,因此可以基于同一个编译结果创建多个 PodGroup。NewPodGroup 根据某个已编译的模板创建运行时 PodGroup,
并指定应基于哪个模板来构建它。
builder := workloadbuilder.NewBuilder(item, opts)
if errs := builder.Validate(ctx, workloadbuilder.ValidationInput{}); len(errs) > 0 {
// 拒绝该请求
}
workload, err := builder.BuildWorkload()
podGroup, err := builder.NewPodGroup("trainer-pg", item.Name)
关于此流程完整、可运行的版本(包括 Job 控制器如何将其串联起来),
请参见包参考中的示例。
验证调度配置
Validate 分两层检查配置:
- 对构建块本身的结构验证:必填字段、取值范围、联合类型中恰好设置一个成员的规则,以及不可变性。
这些检查来自根据 API 类型生成的声明式验证规则。
- 控制器策略检查,这是声明式验证无法表达的:
下文所述的允许列表,以及诸如在
basic 策略下拒绝 all 干扰模式之类的跨字段规则。
验证在创建对象和更新对象时也有所不同。
更新时,该库还会额外强制检查创建后被冻结的字段,
这意味着控制器必须同时提供之前存储的配置和新配置。
创建时没有可比较的对象,因此这些检查不适用。
退出声明式验证
是否需要第一层取决于你的控制器运行在哪里,有一个选项可以控制它:
- 树外控制器保持声明式验证为启用状态,这也是默认行为。
对于自定义资源,没有其他机制会应用这些结构规则,
因此一次
Validate 调用即可覆盖两层。 - 树内控制器会设置
DisableDeclarativeValidation,
因为 API 服务器在验证父对象时已经对内嵌的构建块运行了声明式验证。
跳过第一层可以避免重复检查相同的字段,让 Validate 只运行控制器策略检查。
选择启用调度选项
由于构建块类型由各个控制器共享,未来的发行版本可能会添加对某些控制器并不适用的调度选项。
为防止新选项悄无声息地渗入,workloadbuilder 采用允许列表模型:
控制器声明其支持的策略和干扰模式,Validate 会拒绝该集合之外的任何内容,
并在违规构建块的字段路径处报告错误。
因此,选项默认被拒绝。引入新策略时,现有控制器会一直拒绝它,
直到其维护者扩展允许列表为止;对树外控制器而言,这还意味着要一并更新其 vendor 的库副本。
builder := workloadbuilder.NewBuilder(item, workloadbuilder.BuildOptions{
Owner: owner,
AllowedPolicies: []workloadbuilder.SchedulingPolicyOption{workloadbuilder.BasicPolicy, workloadbuilder.GangPolicy},
AllowedDisruptionModes: []workloadbuilder.DisruptionModeOption{workloadbuilder.SingleMode, workloadbuilder.AllMode},
})
allErrs := builder.Validate(ctx, workloadbuilder.ValidationInput{})
从现有 Workload 生成 PodGroup
当 Workload 已经存在时(无论它是由父控制器编译而来,还是手工创建的),
只管理运行时 PodGroup 的子控制器应改用 NewBuilderFromExistingWorkload。
该构建器使用自己的属主引用,从提供的 Workload 创建 PodGroup 对象。
它不进行任何验证或编译,因此现有的 Workload 永远不会被重新编译。
builder := workloadbuilder.NewBuilderFromExistingWorkload(parentWorkload, workloadbuilder.BuildOptions{Owner: owner})
podGroup, err := builder.NewPodGroup("trainer-pg", "trainer-pgt-0")
接下来