一个集群,多个调度器:Kubernetes 多调度器共存实践指南
一个集群,多个调度器:Kubernetes 多调度器共存实践指南
“我们集群里已经有 kube-scheduler 了,还能再装一个 Volcano 吗?会不会打架?”——这是 AI Infra 团队在做调度器选型时最常被问到的第一个问题。答案是:可以,而且这正是 Kubernetes 的设计初衷之一。但"装上就能用"和"用对"之间,隔着一整篇本文要讲的内容。
一、为什么这个问题重要
大模型时代的集群里,工作负载的分裂前所未有:在线服务要打散、要低延迟;训练任务要 Gang 调度、要拓扑聚拢;推理服务要 SLO 感知、要弹性伸缩。没有任何一个调度器能同时把这些语义做到极致,于是"多调度器共存"从边缘玩法变成了生产标配——华为云 CCE 的"kube-scheduler 管在线 + Volcano 管训练"双轨架构就是典型代表。
Kubernetes 从设计之初就考虑了这个需求:每个 Pod 通过 schedulerName 字段指定由谁来调度,各调度器通过 watch API Server 只处理与自己名称匹配的 Pod,互相不感知、互不干扰。这是所有专用调度器(Volcano、Run:ai、Gödel 等)能够存在的基础机制。
但机制归机制,真正落地时会遇到资源双重记账、抢占互相不知情、拓扑约束不互通这三个经典冲突。本文沿着"机制→模式→坑→实践"的顺序展开。
二、核心机制:schedulerName 路由
先看两个调度器如何分工。每个 Pod 的 spec 中都有一个 schedulerName 字段,默认值为 default-scheduler(即 kube-scheduler)。设为其他值时,Pod 被路由给对应调度器处理。
1 | # 由默认 kube-scheduler 调度(普通无状态服务) |
只要两个调度器都处于 Running 状态,普通服务走 kube-scheduler 的打散策略,训练任务走 Volcano 的 Gang + 拓扑感知策略,各得其所。
这里有个容易被忽略的细节:多个调度器之间没有协调机制。kube-scheduler 不知道 Volcano 的存在,Volcano 也不关心 kube-scheduler 在做什么。它们唯一的共享事实是 etcd 里的节点资源和 Pod 状态——这个"共享"恰恰是所有冲突的根源,也是后文所有坑的出处。
三、四种典型的共存模式
模式一:kube-scheduler + Volcano(最常见)
Volcano 官方设计就是与默认调度器并存而非替代。Volcano 只接管设置了 schedulerName: volcano 的工作负载,其余 Pod 仍由 kube-scheduler 处理。华为云 CCE 等生产环境普遍采用这种架构。
适合场景:AI 训练集群、批处理与在线服务混合部署。
模式二:Kueue 的第三条路(控制器,而非调度器)
Kueue 不是独立调度器,而是一个控制器层的队列管理器——它在 Pod 创建前拦截(通过 admission 或 Job 挂起机制),决定"什么时候允许进入调度",而真正"放在哪个节点"仍由默认调度器完成。
这个设计很聪明:它避免了多调度器并存的复杂性,天然复用了 kube-scheduler 的全部能力(包括 DRA、Topology Manager 等新特性)。代价是 Kueue 无法实现 Volcano 级别的深度调度干预——它管"何时",不管"何地"。
适合场景:GCP 生态(GKE 官方推荐组合是 DWS + Kueue + JobSet)、需要队列配额管理但不需要深度 Gang 语义的团队。
模式三:多 Profile 单进程(轻量替代)
在引入第二调度器之前,值得先评估 K8s 的 Scheduling Profiles 机制:同一个 kube-scheduler 进程可以运行多个逻辑 Profile,每个 Profile 有自己的插件组合和调度器名称。不同 schedulerName 的 Pod 进入不同 Profile,走不同的打分策略——但共享同一个调度循环、同一份资源视图。
适合场景:差异只是"打分策略不同"(比如在线服务要 spread、批处理要 binpack),不需要改变调度循环的根基语义。如果差异到了 Gang 这种级别,Profile 就不够了,需要真正的第二调度器。
模式四:同一调度器多实例分片(吞吐扩展)
当单实例调度器成为吞吐瓶颈(万节点级集群),Volcano 支持部署多个 volcano-scheduler 实例。早期方案通过节点 label 分片(每个调度器负责一组节点),新方案基于 hash 算法自动将 Job 和 Node 分配给不同实例,对用户透明。
适合场景:超大规模集群的调度器水平扩展。
四、三个必须警惕的坑
多调度器共存最大的风险不是"不工作",而是"看起来工作,出问题时才爆发"。以下三个坑都来自同一根源:各调度器只有自己的局部视图。
坑一:资源双重记账
kube-scheduler 基于 Pod 的 resource requests 做调度决策,但它不知道 Volcano 侧 PodGroup 的 minAvailable 语义。极端情况:
- Volcano 视角:一个 1000 卡的训练任务已凑齐 999 个 Worker,正在等待最后 1 个节点的资源释放,集群"逻辑已分配"1000 卡
- kube-scheduler 视角:那个节点还有剩余可分配资源,把它分配给一个刚扩容的在线服务
结果:训练任务永远凑不齐 Gang,而 kube-scheduler 认为一切正常。Volcano 的"预留语义"在 kube-scheduler 眼里就是"空闲"——这不是 bug,是两个调度器对资源语义的理解根本不同。
缓解方案:
- 节点池物理隔离(最推荐):训练任务通过 nodeSelector/taint 约束到专用节点池,从根源上消除竞争
- namespace 隔离 + ResourceQuota:在配额层面划清界限
坑二:抢占互相不知情
Volcano 的 Gang 抢占(v1.15)只会驱逐自己管辖的 Pod,kube-scheduler 的抢占也只考虑默认调度的 Pod。这个坑的底层根因(共享资源视图无分布式锁、优先级语义不互通、抢占路径各自独立)与社区 KEP 演进方向,见 Kubernetes 跨调度器抢占:机制、冲突根因与选型实践。跨调度器的抢占链会导致:
- 一个高优先级 Pod 设置了
schedulerName: default-scheduler,被驱逐对象是 Volcano 管的训练 Worker - kube-scheduler 并不理解"驱逐这个 Worker 会破坏一个 999/1000 的 Gang",照常抢占
- 训练任务整体失败,已消耗的 999 卡时全部浪费
缓解方案:
- 通过 PriorityClass 做全局优先级对齐,确保跨调度器优先级语义一致
- 设置
preemptionPolicy: Never保护关键训练任务,把抢占决策权交给人工或上层编排 - 最根本的:还是物理隔离
坑三:拓扑约束不互通
Volcano 的 HyperNode 拓扑域对 kube-scheduler 完全不可见。反过来,kube-scheduler 的默认 spread 策略也可能把 Volcano 希望聚拢的 TP 通信组打散到不同机架——两个调度器的"好放置"定义相互矛盾。
缓解方案:
- 混部节点池上,为在线服务 Pod 显式设置
topologySpreadConstraints,避免误伤训练任务的通信域 - Volcano 侧通过 HyperNode 硬约束(
highestTierAllowed)兜底,即使 kube-scheduler 打散了部分 Pod,Volcano 管的核心通信组仍能保证拓扑完整
五、实践建议:一套验证过的组合拳
综合社区经验,生产环境"默认调度器 + Volcano"的推荐做法:
第一层:工作负载分工明确
- 在线服务(Deployment/StatefulSet)→ kube-scheduler
- AI 训练和批处理(VolcanoJob、KubeRay、MPIJob)→ 显式指定
schedulerName: volcano - 推理服务 → 视引擎而定:vLLM 原生 Pod 可留在 kube-scheduler + Kueue 组合,需要深度调度(PD 分离编排、KV 路由)时上 Kthena。Kthena 作为 Volcano 子项目正是"第二个调度器"在 LLM 推理场景的具体形态,见 从 KServe 到 Kthena:云原生模型服务平台的技术演进
第二层:节点池物理隔离
训练节点池打 taint + label,在线节点池独立。这一步能同时消除三个坑的绝大多数风险,性价比最高。
第三层:优先级全局对齐
定义统一的 PriorityClass 体系,两个调度器共用同一套优先级数值语义。
第四层:观测各自独立
两套调度器各有自己的 metrics(kube-scheduler 的 scheduler_ 系列、Volcano 的调度延迟/队列深度指标),监控面板分开建设,避免误判。
六、判断框架:什么时候需要第二个调度器
最后给一个决策框架。是否需要多调度器,取决于工作负载的调度语义差异是否大到无法用单一调度器的多 Profile 表达:
1 | 差异只是打分策略不同(spread vs binpack)? |
一个判断:随着 K8s 原生 Gang 调度(v1.35 的 scheduling.k8s.io/v1alpha1)和 DRA 的 GA,"通用调度器"的生态位正在被标准化吞噬。多调度器共存的格局不会消失,但共存的理由会越来越集中到两个点上:拓扑深度感知(标准化尚未触及)和推理专用语义(新赛道)。中间地带的共存需求,未来大概率被上游标准的演进逐步吸收。
本文技术细节参考 Kubernetes 官方文档的 Multiple Schedulers 章节、Volcano 官方文档与设计文档、Kueue 官方文档,以及各云厂商公开技术资料。数据截至 2026 年 8 月,具体版本特性请以官方最新文档为准。

