Kubernetes v1.35:引入工作负载感知调度

调度大型工作负载比调度单个 Pod 更复杂、也更脆弱, 因为它通常需要把所有 Pod 作为整体来考虑,而不是逐个独立调度。 例如,在调度一个机器学习批处理任务时, 你往往需要有策略地放置每个 worker(例如放在同一个机架上), 才能让整体执行效率更高。 同时,这类工作负载中的 Pod 在调度视角下往往非常相似, 这从根本上改变了调度过程应有的形态。

虽然已经有很多定制调度器可以高效处理工作负载调度, 但考虑到工作负载调度对 Kubernetes 用户的普遍性和重要性, 尤其是在 AI 时代用例快速增长的背景下, 现在正是让工作负载成为 kube-scheduler 一等公民、并提供原生支持的时候。

工作负载感知调度

Kubernetes 1.35 最近发布了首批工作负载感知调度能力改进。 这些改进属于一个更广泛的长期计划,目标是提升工作负载的调度与管理能力。 该计划将跨越多个 SIG 和多个发布周期, 逐步扩展系统能力,向其“北极星目标”推进: 在 Kubernetes 中实现无缝的工作负载调度与管理, 包括但不限于抢占和自动伸缩。

Kubernetes v1.35 引入了 Workload API, 你可以用它描述工作负载的目标形态以及面向调度的要求。 它还带来了 编组调度(Gang Scheduling) 的初始实现, 可指示 kube-scheduler全有或全无(all-or-nothing) 方式调度编组 Pod。 最后,我们通过 机会式批处理(Opportunistic batching) 特性提升了相同 Pod(通常构成一个编组)的调度效率, 从而加速整个调度过程。

Workload API

新的 Workload API 资源属于 scheduling.k8s.io/v1alpha1 API 组。 该资源以结构化、机器可读的形式定义多 Pod 应用的调度需求。 像 Job 这类面向用户的工作负载定义“运行什么”, 而 Workload 资源定义“一组 Pod 应如何被调度”, 以及它们在整个生命周期内的放置如何被管理。

Workload 允许你定义一组 Pod,并对其应用调度策略。 下面是一个编组调度配置示例: 你可以定义一个名为 workerspodGroup,并应用 gang 策略,minCount 设置为 4。

apiVersion: scheduling.k8s.io/v1alpha1
kind: Workload
metadata:
  name: training-job-workload
  namespace: some-ns
spec:
  podGroups:
  - name: workers
    policy:
      gang:
        # 仅当 4 个 Pod 能同时运行时,该编组才可调度
        minCount: 4

创建 Pod 时,你可以通过新的 workloadRef 字段把它们关联到这个 Workload:

apiVersion: v1
kind: Pod
metadata:
  name: worker-0
  namespace: some-ns
spec:
  workloadRef:
    name: training-job-workload
    podGroup: workers
  ...

编组调度如何工作

gang 策略会强制执行全有或全无放置。 没有编组调度时,一个 Job 可能只被部分调度, 占用资源却无法真正运行,从而导致资源浪费甚至潜在死锁。

当你创建属于某个编组调度 Pod 组的 Pod 时, 调度器的 GangScheduling 插件会按每个 Pod 组(或副本键)独立管理其生命周期:

  1. 当你创建 Pod(或由控制器代你创建)时, 调度器会先阻止它们被调度,直到:

    • 被引用的 Workload 对象已创建;
    • 被引用的 Pod 组在某个 Workload 中存在;
    • 该组中待调度 Pod 数量满足你的 minCount
  2. 当到达足够数量的 Pod 后,调度器会尝试放置它们。 但这些 Pod 不会立即绑定到节点,而是先在 Permit 门控处等待。

  3. 调度器会检查是否已为整个组(至少达到 minCount)找到有效分配。

    • 如果组有足够空间,门控打开,所有 Pod 绑定到节点。
    • 如果在超时(默认 5 分钟)内仅有子集 Pod 调度成功, 调度器会拒绝该组中的所有 Pod。 它们会返回队列,释放已保留资源给其他工作负载。

需要说明的是,虽然这只是第一版实现, Kubernetes 项目已经明确计划在后续版本持续改进并扩展编组调度算法。 我们希望带来的收益包括: 针对整个编组的单周期调度阶段、工作负载级抢占等, 并持续向北极星目标推进。

Opportunistic batching

除了显式的编组调度,v1.35 还引入了机会式批处理。 这是一个 Beta 特性,可降低相同 Pod 的调度延迟。

与编组调度不同,这个特性不要求启用 Workload API, 也不需要用户显式选择加入。 它在调度器内部以“机会式”方式工作:识别调度要求相同的 Pod (例如容器镜像、资源请求、亲和性等)。 当调度器处理一个 Pod 时, 可以复用该 Pod 的可行性计算结果给队列中后续相同 Pod, 从而显著加速调度。

只要 Pod 满足相应条件,多数用户无需额外操作就能自动受益于这项优化。

限制条件

机会式批处理仅在特定条件下生效。 kube-scheduler 用于寻找放置位置的相关字段,必须在 Pod 之间保持一致。 此外,某些特性的使用会为这些 Pod 禁用批处理机制,以确保正确性。

请注意,你可能需要检查 kube-scheduler 配置, 确保它没有在你不知情的情况下为工作负载隐式禁用批处理。

关于限制条件的更多细节,请参考文档

北极星愿景

该项目有着广泛目标:实现工作负载感知调度。 这些新 API 与调度增强只是第一步。 在近期,工作将重点攻关:

  • 引入工作负载调度阶段
  • 增强多节点 DRA 与拓扑感知调度支持
  • 工作负载级抢占
  • 增强调度与自动伸缩的集成
  • 增强与外部工作负载调度器的交互
  • 覆盖工作负载全生命周期的放置管理
  • 多工作负载调度模拟

以及更多方向。上述重点的优先级和实现顺序可能会调整,敬请关注后续更新。

快速开始

要体验工作负载感知调度改进:

  • Workload API:在 kube-apiserverkube-scheduler 上启用 GenericWorkload 特性门控,并确保启用 scheduling.k8s.io/v1alpha1 API 组
  • 编组调度:在 kube-scheduler 上启用 GangScheduling 特性门控(要求 Workload API 已启用)。
  • 机会式批处理:该 Beta 特性在 v1.35 默认启用。 如有需要,可在 kube-scheduler 上通过 OpportunisticBatching 特性门控将其关闭。

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

了解更多