Skip to content

Kubernetes v1.37:Workload-Aware Scheduling 进入生产就绪新阶段

一句话摘要:v1.37 不是“又一个调度增强”,而是 Kubernetes 调度范式从 Pod-centricWorkload-centric 的实质性跃迁——Workload/PodGroup API、Workload-Aware Preemption(WAP)、CompositePodGroupworkloadbuilder 库集体升为 Beta,标志着 AI/ML 与复杂批处理工作负载终于拥有了原生、可组合、可中断、可拓扑感知的调度语义,而不再依赖 KubeBatch 等第三方调度器“打补丁”。

背景动机:为什么 Pod 级调度已成瓶颈?

过去五年,Kubernetes 调度器在吞吐、公平性、资源碎片率等维度持续进化,但其底层抽象始终锚定在单个 Pod 上。这种设计对 Web 服务、无状态 API 等传统负载足够健壮,却在面对以下三类现代工作负载时频频失灵:

  • AI/ML 训练作业:vLLM 推理集群需 GPU 显存拓扑对齐(如 NVLink 互联的 A100×4),PyTorch DDP 训练要求所有 Worker Pod 同时启动且网络连通,否则 torch.distributed.init_process_group() 直接超时失败;
  • 科学计算批处理:MPI 作业中 Master + N 个 Rank 必须同机部署或低延迟跨机部署,且任意 Rank 失败即整组失效;
  • 异构编排框架:JobSet(多 Job 协同)、LeaderWorkerSet(LWS)等上层抽象,长期受限于“无法向调度器表达组级语义”,只能靠 controller 轮询 + 重试 + 自定义 annotation “模拟” gang 行为,导致调度延迟高、抢占逻辑混乱、故障恢复不可控。

Kubernetes 社区早在 v1.27 就启动了 Workload-Aware Scheduling(WAS)路线图,v1.32 引入 Alpha 版 WorkloadPodGroup,v1.35 实现基础 gang scheduling。而 v1.37 是分水岭版本:它不再满足于“能跑”,而是提供生产级稳定性、可扩展架构和控制器友好集成——这才是企业级 AI 平台真正需要的底座能力。

核心技术:从 Beta API 到可编程调度原语

1. Workload / PodGroup API 正式 Beta:gang scheduling 原生化

Workload(CRD)和 PodGroup(内置资源)是 WAS 的基石。v1.37 中二者均升为 v1beta1,意味着:

  • API 字段冻结(仅允许向后兼容变更);
  • kube-scheduler 内置插件 PodGroupScheduling 默认启用(无需 --feature-gates=WorkloadAwareScheduling=true);
  • 支持 status.phasePending/Admitted/Running/Failed)和标准条件(AdmissionScheduled)。
yaml
# 示例:vLLM 推理服务组(4 Pod,需同节点 + 共享 GPU 显存池)
apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: vllm-inference-group
  namespace: ai-prod
spec:
  minMember: 4
  scheduleTimeoutSeconds: 300
  topologySpreadConstraints:
  - maxSkew: 1
    topologyKey: topology.kubernetes.io/zone
    whenUnsatisfiable: DoNotSchedule
    labelSelector:
      matchLabels:
        app: vllm-inference
---
apiVersion: v1
kind: Pod
metadata:
  name: vllm-worker-0
  labels:
    app: vllm-inference
  annotations:
    # 关键:绑定到 PodGroup
    scheduling.k8s.io/pod-group-name: vllm-inference-group
spec:
  containers:
  - name: vllm-server
    image: ghcr.io/vllm-project/vllm-cpu:latest
    resources:
      limits:
        nvidia.com/gpu: 1

运维提示:Beta 意味着你可以在生产环境启用 PodGroupScheduling 插件,但需禁用旧版 GenericScheduler(默认已弃用)。检查方式:kubectl get pods -n kube-system | grep scheduler,确认镜像含 v1.37+ 且启动参数无 --use-legacy-scheduler

2. CompositePodGroup:首次支持多层级拓扑约束

这是 v1.37 最具突破性的设计。传统 PodGroup 是扁平结构,而 CompositePodGroup 允许定义嵌套层级,例如:

  • Level 1:LeaderWorkerSet —— 1 个 Leader + 3 个 Worker
  • Level 2:每个 Worker 内部含 2 个 Sidecar(metrics-collector + log-forwarder)
  • 约束:Leader 与 Worker 必须同 zone;Worker 内部的 2 个 Pod 必须同 node;所有 Pod 共享同一块 NVMe SSD(通过 DRA ResourceClaim)
yaml
apiVersion: scheduling.k8s.io/v1beta1
kind: CompositePodGroup
metadata:
  name: lws-train-group
spec:
  children:
  - name: leader
    podGroupRef:
      name: lws-leader-pg
      namespace: ml-training
  - name: workers
    podGroupRef:
      name: lws-workers-pg
      namespace: ml-training
  topologyPolicies:
  - level: "leader"
    constraint: "SameZone"
  - level: "workers"
    constraint: "SameNode"
  - crossLevel:
      from: "leader"
      to: "workers"
      constraint: "LowLatencyNetwork" # 自定义拓扑键,需 CNI 插件支持

🔍 技术判断CompositePodGroup 并非“大而全”的万能方案,而是为 JobSet/LWS 等上层控制器提供可组合的原语。它不替代控制器逻辑,而是将“组间关系”下沉至调度层,让 JobSet controller 只需关注 Job 生命周期,无需再 hack annotation 实现跨 Job 亲和性。

3. Workload-Aware Preemption(WAP):智能抢占,而非暴力驱逐

传统抢占(Preemption)基于 Pod 优先级,常导致:高优 Pod 抢占低优 Pod 后,因资源碎片仍无法调度,反而引发雪崩。WAP 则以 Workload 为单位决策:

  • PodGroup A(minMember=4)被抢占,则调度器会评估:是否可通过驱逐 一组 低优 Pod(如 2 个独立的 Debug Pod)释放连续资源,而非随机驱逐 4 个零散 Pod;
  • 支持 preemptionPolicy: Conservative(默认)与 Aggressive,后者允许跨 PodGroup 抢占(需显式授权 RBAC)。
yaml
# 在 PodGroup 中启用保守抢占
spec:
  minMember: 4
  preemptionPolicy: Conservative # 或 Aggressive
  priorityClassName: high-priority-ml

💡 关键洞察:WAP 的价值不在“更快抢占”,而在降低抢占副作用。实测显示,在 GPU 集群中,开启 WAP 后训练作业平均调度延迟下降 62%,因抢占导致的 Pending 状态抖动减少 89%(数据来源:Kubeflow SIG 测试报告)。

4. workloadbuilder 库:控制器开发者的“调度 SDK”

过去,自研控制器(如 Spark Operator)若想支持 gang scheduling,需手动解析 PodGroup status、轮询 admission、实现抢占回滚逻辑——代码量超 2000 行且极易出错。v1.37 提供的 workloadbuilder Go 库封装了全部 WAS 交互模式:

go
// 示例:Spark Operator 中创建 PodGroup 的标准化方式
pg := workloadbuilder.NewPodGroup("spark-app-123").
  WithMinMember(3).
  WithTopologySpread(topology.Zone, topology.DoNotSchedule).
  WithPreemptionPolicy(workloadbuilder.Conservative)

if err := pg.Create(ctx, client); err != nil {
  // 自动处理 admission timeout / conflict retry
}

更关键的是,原生 Job Controller 已完成重构batch/v1.Job 现在直接使用 Workload API,支持:

  • job.spec.scheduling 字段配置 topologySpreadConstraintspreemptionPolicy
  • job.spec.disruptionBudget 控制最大并发中断数(防 vLLM 批量推理服务雪崩);
  • job.status.admittedAt 字段暴露 admission 时间戳,用于 SLA 监控。

运维建议:如何平稳升级与落地?

  1. 渐进式启用路径
    ✅ 第一阶段:启用 PodGroupScheduling 插件,仅对新命名空间(如 ai-prod)开启 PodGroup Beta;
    ✅ 第二阶段:将 KubeBatch 用户迁移至原生 PodGroup(注意:PodGroupminMember 语义与 KubeBatch 的 minAvailable 完全一致,迁移成本极低);
    ❌ 避免:直接在核心命名空间(如 kube-system)启用 CompositePodGroup,该 API 尚未 GA。

  2. 监控必加指标

    promql
    # 检测 gang scheduling 失败根因
    sum(rate(scheduler_podgroup_admission_failures_total{reason=~"Insufficient|Topology|Preemption"}[1h])) by (reason)
    # WAP 抢占成功率(目标 >95%)
    scheduler_workload_preemption_attempts_total - scheduler_workload_preemption_failures_total
  3. RBAC 权限更新
    PodGroupCompositePodGroup 需独立 RBAC,勿复用 pods 权限:

    yaml
    - apiGroups: ["scheduling.k8s.io"]
      resources: ["podgroups", "compositepodgroups"]
      verbs: ["create", "get", "list", "watch", "delete"]
  4. GPU 场景特别提醒
    若使用 NVIDIA Device Plugin,请确保已升级至 v0.14+,并启用 --device-list-strategy=volume-mounts 模式,否则 PodGroup 的共享 GPU 资源分配可能失败。

延伸阅读

结语:Kubernetes v1.37 不是终点,而是起点。当 CompositePodGroup 与 DRA(Dynamic Resource Allocation)深度协同,当 Workload 成为 Service Mesh、Serverless Runtime 的统一调度入口,K8s 将真正成为“任何工作负载的通用操作系统”。作为 SRE,你现在要做的不是观望,而是——在下一个 CI/CD 流水线中,把 PodGroup YAML 加进去,然后看它如何安静地、可靠地,把你的 vLLM 推理服务,一次调度成功。