Kubernetes v1.36:推进工作负载感知调度

来源: Kubernetes 博客
原文链接:https://kubernetes.io/blog/2026/05/13/kubernetes-v1-36-advancing-workload-aware-scheduling/


Maciej Skoczeń (Google)、Antoni Zawodny (Google)、Matt Matejczyk (Google)、Bartosz Rejman (Google)、Jon Huhn (Microsoft)、Maciej Wyrzuc (Google)、Heba Elayoty (Microsoft) 撰写 | 2026年5月13日,星期三

AI/ML 和批处理工作负载带来了独特的调度挑战,这些挑战超越了简单的逐 Pod 调度。在 Kubernetes v1.35 中,我们引入了首批 工作负载感知调度 改进,包括基础的 Workload API、基于 Pod 框架的基本 组调度(gang scheduling)支持,以及用于高效处理相同 Pod 的 机会性批处理(opportunistic batching)功能。

Kubernetes v1.36 引入了一项重要的架构演进,通过清晰分离 API 关注点:Workload API 作为静态模板,而新的 PodGroup API 负责处理运行时状态。为此,kube-scheduler 新增了一个 PodGroup 调度周期,支持原子化工作负载处理,并为未来增强功能铺平了道路。此版本还首次推出了 拓扑感知调度(topology-aware scheduling)和 工作负载感知抢占(workload-aware preemption)的初始迭代,以提升调度能力。此外,工作负载的 ResourceClaim 支持 为 PodGroup 解锁了 动态资源分配DRA)。最后,为了展示实际就绪状态,v1.36 交付了 Job 控制器与新 API 集成的第一阶段。

Workload 和 PodGroup API 更新

Workload API 现在作为静态模板,而新的 PodGroup API 描述运行时对象。Kubernetes v1.36 将 Workload 和 PodGroup API 作为 scheduling.k8s.io/v1alpha2API 组 的一部分引入,完全取代了之前的 v1alpha1 API 版本。

在 v1.35 中,Pod 组及其运行时状态嵌入在 Workload 资源中。新模型将这些概念解耦:Workload 现在作为静态模板对象,而 PodGroup 管理运行时状态。这种分离还提高了性能和可扩展性,因为 PodGroup API 允许对状态更新进行按副本分片。

由于 Workload API 仅作为模板,kube-scheduler 的逻辑得以简化。调度器可以直接读取 PodGroup,其中包含调度器所需的所有信息,而无需监视或解析 Workload 对象本身。

以下是更新后的配置示例。工作负载控制器(如 Job 控制器)定义 Workload 对象,该对象现在作为 Pod 组的静态模板:

apiVersion: scheduling.k8s.io/v1alpha2
kind: Workload
metadata:
  name: training-job-workload
  namespace: some-ns
spec:
  # Pod groups are now defined as templates,
  # which contains the PodGroup objects' spec fields.
  podGroupTemplates:
  - name: workers
    schedulingPolicy:
      gang:
        # The gang is schedulable only if 4 pods can run at once
        minCount: 4

Controllers then stamp out runtime PodGroup instances based on those templates. The PodGroup runtime object holds the actual scheduling policy and references the template from which it was created. It also has a status containing conditions that mirror the states of individual Pods, reflecting the overall scheduling state of the group:

控制器随后基于这些模板生成运行时 PodGroup(Pod组)实例。PodGroup 运行时对象持有实际的调度策略,并引用创建它的模板。它还包含一个状态,其中包含反映各个 Pod 状态的条件,从而体现该组的整体调度状态:

apiVersion: scheduling.k8s.io/v1alpha2
kind: PodGroup
metadata:
  name: training-job-workers-pg
  namespace: some-ns
spec:
  # The PodGroup references the Workload template it originated from.
  # In comparison, .metadata.ownerReferences points to the "true" workload object,
  # e.g., a Job. 
  podGroupTemplateRef:
    workload:
      workloadName: training-job-workload
      podGroupTemplateName: workers
  # The actual scheduling policy is placed inside the runtime PodGroup
  schedulingPolicy:
    gang:
      minCount: 4
status:
  # The status contains conditions mirroring individual Pod conditions.
  conditions:
  - type: PodGroupScheduled
    status: "True"
    lastTransitionTime: 2026-04-03T00:00:00Z

最后,为了将这一新架构与各个 Pod(容器组)连接起来,Pod API 中的 workloadRef 字段已被替换为 schedulingGroup 字段。在创建 Pod 时,你可以直接将它们链接到运行时 PodGroup:

apiVersion: v1
kind: Pod
metadata:
  name: worker-0
  namespace: some-ns
spec:
  # The workloadRef field has been replaced by schedulingGroup
  schedulingGroup:
    podGroupName: training-job-workers-pg
  ...

通过将工作负载(Workload)保持为静态模板,并将 PodGroup 提升为一等公民的独立 API,我们为在未来的 Kubernetes 版本中构建高级工作负载调度能力奠定了坚实基础。

PodGroup 调度周期与 Gang 调度

为了高效管理这些工作负载,kube-scheduler 现在具备一个专用的 PodGroup 调度周期。调度器不再逐个 Pod 顺序评估和预留资源(这可能导致调度死锁),而是将整个组作为一个统一操作进行评估。

当调度器从调度队列中弹出一个 PodGroup 成员时,无论该组的具体策略如何,它都会获取该组中其余已入队的 Pod,按确定性顺序排序,并执行如下的原子调度周期:

  1. 调度器对集群状态进行一次快照,以防止竞态条件,并确保在评估整个组时的一致性。

后,它尝试使用 PodGroup 调度算法为组内所有 Pod 找到有效的节点(Node)放置位置,该算法利用了标准的基于 Pod 的过滤和评分阶段。

  1. 根据算法的结果,调度决策会以原子方式应用于整个 PodGroup。
    1. 成功:如果找到了放置位置且满足组约束,则可调度的成员 Pod 会一起直接进入绑定阶段。任何剩余不可调度的 Pod 会被返回调度队列,等待可用资源,以便它们能够加入已调度的 Pod。(注意:如果在其他 Pod 已被调度后,又有新的 Pod 加入 PodGroup,该周期会在考虑已有 Pod 的情况下评估新 Pod。关键在于,已分配到节点的 Pod 会保持运行状态。即使后续周期中组未能满足其要求,调度器也不会取消分配或驱逐它们。)
    2. 失败:如果组未能满足其要求,则整个组被视为不可调度。所有 Pod 都不会被绑定,它们会在退避期后被返回调度队列以稍后重试。

该周期构成了 Gang 调度的基础。当你的工作负载需要严格的“全有或全无”放置时,gang 策略会利用该周期来防止导致资源浪费和潜在死锁的部分部署。

虽然调度器在满足 minCount 要求之前仍会将 Pod 保持在 PreEnqueue 阶段,但实际的调度阶段现在完全依赖于新的 PodGroup 周期。具体来说,在算法执行期间,调度器会验证可调度的 Pod 数量是否满足 minCount。如果集群无法容纳所需的最小数量,则所有 Pod 都不会被绑定。该组失败,并等待足够的资源释放。

限制

PodGroup 调度周期的第一个版本存在某些限制:

  • 对于基本的同质 Pod 组(即所有 Pod 具有相同的调度要求,且没有 Pod 间依赖关系,如亲和性、反亲和性或拓扑分布约束),如果存在有效放置位置,算法预计能够找到。
  • 对于异质 Pod 组,即使解决方案看似简单,也无法保证一定能找到有效放置位置。
  • 对于具有 Pod 间依赖关系的 Pod 组,无法保证一定能找到有效放置位置。

除上述情况外,对于涉及组内依赖关系的情况(例如,一个 Pod 的可调度性通过 Pod 间亲和性依赖于另一个组成员),由于算法的确定性处理顺序,无论集群状态如何,该算法都可能无法找到放置位置。

拓扑感知调度

对于 AI/ML 训练或批处理等复杂的分布式工作负载,将 Pod 随机分布在集群中可能会引入显著的网络延迟并成为整体性能的瓶颈。

拓扑感知调度通过允许你直接在 PodGroup 上定义拓扑约束来解决此问题,确保其 Pod 被共同放置在特定的物理或逻辑域内:

apiVersion: scheduling.k8s.io/v1alpha2
kind: PodGroup
metadata:
  name: topology-aware-workers-pg
spec:
  schedulingPolicy:
    gang:
      minCount: 4
  # Enforce that the pods are co-located based on the rack topology
  schedulingConstraints:
    topology:
      - key: topology.kubernetes.io/rack

在此示例中,kube-scheduler 尝试将 Pods 调度到符合 rack 拓扑约束的各种节点组合上。然后,它根据 PodGroup 利用资源的效率以及在该域内可以成功调度的 Pod 数量,选择最优的放置方案。

为了实现这一点,调度器通过一个专用的基于放置的算法扩展了 PodGroup 调度周期,该算法包含三个阶段:

  1. 根据 PodGroup 的调度约束生成候选放置方案(理论上可行的节点子集)。拓扑感知调度插件使用新的 PlacementGenerate 扩展点来创建这些放置方案。
  2. 评估每个提议的放置方案,以确认整个 PodGroup 是否真的可以容纳在那里。
  3. 对所有可行的放置方案进行评分,为 PodGroup 选择最佳适配。拓扑感知调度插件使用新的 PlacementScore 扩展点对这些放置方案进行评分。

目前,拓扑感知调度不会触发 Pod 抢占来满足约束。然而,我们计划在即将发布的版本中将工作负载感知抢占与拓扑约束集成。

虽然 Kubernetes v1.36 提供了这一基础性的拓扑感知调度,但 Kubernetes 项目计划很快扩展其能力。未来的更新将引入对多拓扑层级、软约束(偏好)、与动态资源分配(DRA)的更深度集成,以及与 basic 调度策略配合时更稳健的行为。

工作负载感知抢占

为了支持新的 PodGroup 调度周期,Kubernetes v1.36 引入了一种新的抢占机制,称为 工作负载感知抢占。当 PodGroup 无法被调度时,调度器会利用该机制尝试使该 PodGroup 的调度成为可能。

与标准逐 Pod 调度周期中使用的默认抢占相比,这种新机制将整个 PodGroup 视为一个单一的抢占者单元。它不会在每个节点上单独评估抢占受害者,而是在整个集群中进行搜索。这使得调度器能够同时从多个节点抢占 Pods,从而为后续调度整个 PodGroup 腾出足够的空间。

工作负载感知抢占还直接在 PodGroup API 中引入了两个额外的概念:

  • PodGroup priority(优先级),覆盖组成 PodGroup 的各个 Pod 的优先级。
  • PodGroup disruptionMode(中断模式),决定 PodGroup 内的 Pods 是否可以独立被抢占,还是必须以 全有或全无 的方式一起被抢占。

在 Kubernetes v1.36 中,这些字段仅受工作负载感知抢占机制尊重。负责这组功能的人员希望在未来的版本中将这些字段的支持扩展到其他中断源,包括逐 Pod 调度周期中使用的默认抢占。

apiVersion: scheduling.k8s.io/v1alpha2
kind: PodGroup
metadata:
  name: victim-pg
spec:
  priorityClassName: high-priority
  priority: 1000
  disruptionMode: PodGroup

在这个例子中,当调度器在工作负载感知的抢占周期中将 victim-pg 评估为潜在的抢占受害者时,它将使用 1000 作为其优先级,并以严格的全有或全无方式抢占该 PodGroup。

工作负载的 DRA ResourceClaim 支持

自 Kubernetes v1.34 正式发布以来,DRA(动态资源分配,Dynamic Resource Allocation)已使 Pod 能够对 设备(如 GPU、TPU 和 NIC)进行详细请求。请求的设备可以被多个通过名称请求相同 ResourceClaim 的 Pod 共享。其他请求可以通过 ResourceClaimTemplate 进行复制,此时 Kubernetes 会为每个引用该模板的 Pod 生成一个名称不确定的 ResourceClaim。然而,对于需要特定 Pod 共享特定设备的大规模工作负载,目前仍需自行管理创建独立的 ResourceClaim。

现在,除了 Pod 之外,PodGroup 也可以作为 ResourceClaimTemplate 的可复制单元。对于 PodGroup 的 spec.resourceClaims 中引用的 ResourceClaimTemplate,无论该组中有多少个 Pod,Kubernetes 都会为整个 PodGroup 生成一个 ResourceClaim。当 Pod 的 spec.resourceClaims 中针对某个 ResourceClaimTemplate 的声明与所属 PodGroup 的 spec.resourceClaims 中的声明匹配时,该 Pod 的声明将解析为为该 PodGroup 生成的 ResourceClaim,而不会为该 Pod 单独生成 ResourceClaim。Workload 对象中的单个 PodGroupTemplate 可以表达资源请求,这些请求既会为每个不同的 PodGroup 进行复制,又可以在每个组内的 Pod 之间共享。

以下示例展示了两个 Pod 请求为其 PodGroup 从 ResourceClaimTemplate 生成的同一个 ResourceClaim:

apiVersion: scheduling.k8s.io/v1alpha2
kind: PodGroup
metadata:
  name: training-job-workers-pg
spec:
  ...
  resourceClaims:
    - name: pg-claim
      resourceClaimTemplateName: my-claim-template
---
apiVersion: v1
kind: Pod
metadata:
  name: topology-aware-workers-pg-pod-1
spec:
  ...
  schedulingGroup:
    podGroupName: training-job-workers-pg
  resourceClaims:
    - name: pg-claim
      resourceClaimTemplateName: my-claim-template
---
apiVersion: v1
kind: Pod
metadata:
  name: topology-aware-workers-pg-pod-2
spec:
  ...
  schedulingGroup:
    podGroupName: training-job-workers-pg
  resourceClaims:
    - name: pg-claim
      resourceClaimTemplateName: my-claim-template

此外,PodGroup 引用的 ResourceClaims(无论是通过 resourceClaimName 还是由 resourceClaimTemplateName 生成的声明)都会为整个 PodGroup 保留。此前,kube-scheduler 只能在 ResourceClaim 的 status.reservedFor 字段中列出单个 Pod,该字段限制为 256 项。现在,status.reservedFor 中的单个 PodGroup 引用可以代表远超 256 个 Pod,从而支持高基数(high-cardinality)的设备共享。

这些变更共同使得具有复杂拓扑的大规模工作负载能够利用 DRA(Dynamic Resource Allocation,动态资源分配)实现可扩展的设备管理。

与 Job 控制器的集成

在 Kubernetes v1.36 中,Job 控制器可以代表你创建和管理 Workload 及 PodGroup 对象,这样代表紧密耦合并行应用(例如分布式 AI 训练)的 Job 无需额外工具即可实现组调度(gang-scheduling)。如果没有此集成,你需要自行创建 Workload 和 PodGroup,并将它们的引用写入 Pod 模板。现在,Job 控制器原生地自动化了这一过程。

当启用了 WorkloadWithJob 特性门控时,Job 控制器会自动:

  • 为每个符合条件的 Job 创建一个 Workload 及对应的运行时 PodGroup,
  • .spec.schedulingGroup 设置到 Job 创建的每个 Pod 上,以便调度器将它们视为一个组(gang),
  • 将 Job 设置为所生成对象的属主,这样当 Job 被删除时,这些对象会被垃圾回收。

集成何时生效?

为了保持首个特性迭代的可预测性,Job 控制器仅在 Job 具有明确、固定的形态时才会创建 Workload 和 PodGroup:

  • .spec.parallelism 大于 1
  • .spec.completionMode 设置为 Indexed
  • .spec.completions 等于 .spec.parallelism
  • Pod 模板上尚未设置 schedulingGroup

这些条件描述了组调度可以处理的 Job 类别:每个 Pod 具有稳定的标识(Indexed),组大小在准入时已知且固定(parallelism == completions),并且没有其他控制器已经声明了调度责任(schedulingGroup 字段未设置)。不满足这些条件的 Job 将像以前一样逐个 Pod 进行调度。

如果你自己在 Pod 模板上设置了 schedulingGroup(例如,因为更高级别的控制器正在管理工作负载),Job 控制器会保持 Pod 模板不变,并且不会创建自己的 Workload 或 PodGroup。这使得该特性在已使用外部批处理系统的集群中启用时是安全的。

以下是一个符合组调度条件的 Job 示例:

apiVersion: batch/v1
kind: Job
metadata:
  name: training-job
  namespace: job-ns
spec:
  completionMode: Indexed
  parallelism: 4
  completions: 4
  template:
    spec:
      restartPolicy: Never
      containers:
      - name: worker
        image: registry.example/trainer:latest

Job(任务)控制器会创建一个归属于该 Job 的 Workload(工作负载)和 PodGroup(Pod 组),并且它创建的每个 Pod 都携带一个 .spec.schedulingGroup 字段,指向所生成的 PodGroup。一旦所有四个 Pod 能够同时放置(使用本文前面描述的 PodGroup 调度周期),这些 Pod 就会被一起调度。

尚未覆盖的内容

当前的约束将这种集成限制为静态、索引式、完全并行的 Job。对其他工作负载形态的支持,包括弹性 Job 和其他内置控制器,已在 KEP-5547 中跟踪。

在未来的 Kubernetes 版本中,这种集成将扩展到支持更多工作负载控制器,并且当前对 Job 的约束可能会放宽。

下一步是什么?

工作负载感知调度的旅程并未止步于此。对于 v1.37,社区正在积极致力于:

  • 将 Workload 和 PodGroup API 升级至 Beta: 我们的首要目标是将 Workload 和 PodGroup API 成熟到 Beta 阶段,巩固它们在 Kubernetes 生态系统中的基础地位。作为此升级过程的一部分,我们还计划引入 minCount 的可变性,以解锁弹性 Job,并允许动态工作负载高效扩展。
  • 多级工作负载层次结构: 为了支持复杂的现代 AI 工作负载(如 JobSet 或通过 LeaderWorkerSet (LWS) 实现的分解推理),我们正在扩展架构以支持多级层次结构。我们计划引入一个新的 API,允许将多个 PodGroup 分组为层次结构,直接反映真实世界工作负载控制器的组织方式。
  • 将高级调度功能升级至 Beta: 我们专注于推动更广泛的工作负载感知调度生态系统的成熟。这包括将现有功能(如拓扑感知调度和工作负载感知抢占)提升到 Beta 阶段。
  • 统一的控制器集成 API: 为了简化采用,我们正在开发一个控制器集成 API。这将为真实世界的工作负载控制器提供一种统一、标准化的方法来使用工作负载感知调度能力。

这些重点领域的优先级和实现顺序可能会发生变化。请继续关注后续更新。

开始使用

以下所有工作负载感知调度改进在 v1.36 中均作为 Alpha 功能提供。要试用它们,您必须配置以下内容:

  • 前提条件: Workload 和 PodGroup API 支持:在 kube-apiserverkube-scheduler 上启用 GenericWorkload 特性门控,并确保 scheduling.k8s.io/v1alpha2API 组已启用。

满足前提条件后,您可以启用特定功能:

  • Gang 调度:kube-scheduler 上启用 GangScheduling 特性门控。
  • 拓扑感知调度:kube-scheduler 上启用 TopologyAwareWorkloadScheduling 特性门控。
  • 工作负载感知抢占:kube-scheduler 上启用 WorkloadAwarePreemption 特性门控(需要同时启用 GangScheduling)。
  • 工作负载的 DRA ResourceClaim 支持:kube-apiserverkube-controller-managerkube-schedulerkubelet 上启用 DRAWorkloadResourceClaims 特性门控。
  • Workload API 与 Job 控制器的集成:kube-apiserverkube-controller-manager 上启用 WorkloadWithJob 特性门控。

我们鼓励您在测试集群中试用工作负载感知调度,并分享您的经验,以帮助塑造 Kubernetes 调度的未来。您可以通过以下方式发送反馈:

了解更多

要深入了解这些功能的架构和设计,请阅读 KEP: