2026 年 9 月 8 日,Kubernetes 官方博客发布了 v1.37 版本的负载感知调度进展。结论先行:Workload 与 PodGroup 两个 API 正式毕业到 Beta,这是 gang 调度(整组调度)在 Kubernetes 里迈向稳定的关键一步;同时新增 CompositePodGroup API 支持多层级整组调度,Job(批处理任务)也获得了直接声明调度策略的字段。对跑分布式 AI 训练、批处理任务的团队来说,「一组任务要么全部一起启动、要么一个都不启动」的能力离生产可用又近了一步。

先交代背景。Kubernetes 是由 Google 开源、如今由云原生计算基金会托管的容器编排平台:它管理着成百上千台服务器上的应用容器,负责决定每个容器放哪台机器、坏了怎么拉起来。这个「决定放哪」的环节叫调度(scheduling),由内置调度器 kube-scheduler 完成。

过去调度器按单个 Pod 排队——Pod 是 Kubernetes 的最小部署单元,可以理解为一个或几个容器组成的运行体。谁先来谁先占资源。这套逻辑对网站类服务没问题,但对 AI 训练、分布式计算这类任务不适用:这类任务由一组 Pod 协作完成,必须全员到齐才能开工。典型例子:一个分布式训练任务由 4 个 worker(执行训练的进程)和 1 个 driver(协调指挥的进程)组成,5 个 Pod 全部跑起来训练才开始。如果调度器只让 4 个 worker 先上了机器,它们占着 GPU 干等第 5 个,任务卡死,宝贵的 GPU 也空转。

gang 调度(gang scheduling,gang 取「一伙人同进同出」之意)解决的就是这个问题:把一组 Pod 当作整体调度,资源足够就整组一起启动,不够就整组一起排队等待,绝不出现「半个任务」占着资源不干活。Workload 是这类任务的描述模板(声明「我要什么样的一组 Pod」),PodGroup 是运行时的状态记录(描述「这组 Pod 此刻进展如何」)。v1.37 之前它们都还是 alpha 阶段的实验特性。

Workload 与 PodGroup API 毕业到 Beta

v1.37 的具体变化:

  • 版本号升到 v1beta1,距离正式稳定版(GA)只差一步。此前测试用的 v1alpha2 整体替换为 v1alpha3,围绕 disruptionMode 字段做了破坏性调整。
  • 排队方式改变:过去同一个 PodGroup 下的 Pod 各自排队,现在调度队列直接登记 PodGroup 本身,整组成员共享同一条排队路径。
  • minCount(整组调度要求的最少 Pod 数)从不可修改变为运行时可改:任务运行中可以动态调整组的最小规模,不打断已经跑起来的 Pod。
  • 抢占(preemption,即调度器把低优先级任务停下、给高优先级任务腾位置)逻辑并入 GenericWorkload 功能开关,原先独立的 WorkloadAwarePreemption 开关取消;算法上也做了提速——只需完整跑一次调度模拟,之后逐个检查被抢占者能否「复活」,不用每救一个就重算一遍。
  • 默认抢占现在认识 PodGroup 了:v1.36 里默认抢占可能只打断组内单个 Pod,v1.37 起会尊重 PodGroup 声明的 disruptionMode(任务可被打断的方式)。

disruptionMode 有两个取值:all 表示整组只能一起动(全有或全无);single 表示允许个别成员单独被打断。这次升级把取值名称也理顺了——旧的 PodGroup 改名为 all,旧的 Pod 改名为 single,命名不再跟 PodGroup 对象绑定,PodGroup 与 CompositePodGroup 共用一套词汇。

CompositePodGroup:组中套组的层级调度

v1.36 的负载感知调度只能描述一层扁平的任务组;v1.37 新增 CompositePodGroup API(alpha 阶段),支持「组里套组」的树形组织。

还是那个 4 个 worker + 1 个 driver 的例子。现在可以把整个训练任务声明成一棵两层树:根组要求「两个孩子组同时满足条件」(minGroupCount: 2);worker 子组要求「至少 4 个 Pod 就绪」(minCount: 4);driver 子组要求「至少 1 个就绪」(minCount: 1)。调度器从根到叶递归检查,任一层不满足,整棵树一起等待,一个 Pod 都不落下——避免任务跑一半卡死。

树形结构还解决了拓扑感知的细粒度问题。拓扑约束指的是「任务必须跑在物理上靠近的机器上」这类位置要求。多级场景很常见:整个任务要求落在同一个可用区(zone,可理解为同一数据中心内的独立故障区域),而 worker 和 driver 又要分别挤在同一批机架(rack)内。v1.37 支持在根组上声明 zone 级约束、子组上声明 rack 级约束,调度器自顶向下逐层求解。

Job 集成与 workloadbuilder 库

API 只是底层;多数用户实际用的是 Job——Kubernetes 里声明批处理任务的对象。v1.37 的 Job 新增 .spec.scheduling 字段,可以直接声明:

  • schedulingPolicy:basic(默认的逐个调度)或 gang(整组调度);
  • schedulingConstraints:拓扑约束,比如限定 Pod 必须落在同一可用区;
  • disruptionMode:single 或 all,任务可被打断的方式;
  • resourceClaims:整组共享的资源声明。

配合这套字段,官方还发布了 Go 语言库 workloadbuilder,把上述调度意图翻译成底层 API 对象,供 JobSet、LeaderWorkerSet 这类上层批处理框架以及自研控制器调用,省去重复造轮子。

使用提醒:默认全部关闭

v1.37 的这些调度能力默认都是关闭的,需要运维在集群各组件上手动打开功能开关(feature gate)才会生效:

  • Beta 级:GenericWorkload(Workload/PodGroup、gang 调度与抢占)、DRAWorkloadResourceClaims(动态分配的资源声明可被整组共享——即 GPU 等硬件资源按组预留、组内 Pod 共用);
  • Alpha 级:TopologyAwareWorkloadScheduling、CompositePodGroup、WorkloadWithJob(Job 集成)、PodGroupPreemptionPolicy。

Kubernetes 负载感知调度工作组已公布 v1.38 的初步计划:Workload 与 PodGroup 升到 GA,拓扑感知调度与 CompositePodGroup 升 Beta,并继续加深与 JobSet、Kueue 等上层任务编排器的集成。

如果你所在的团队正被「GPU 被半个训练任务占住」的问题困扰,可以在测试集群打开 GenericWorkload 开关,从给 Job 声明 schedulingPolicy: gang 开始试起。