kube-scheduler 完整工作原理
1. 整体定位
kube-scheduler 是 Kubernetes 控制平面核心组件,负责为未绑定节点的 Pod 筛选最优节点。
- 监听 APIServer,持续获取
spec.nodeName=""(未调度)的 Pod; - 依据节点资源、标签、亲和、污点、拓扑约束等规则筛选打分;
- 将最优节点绑定给 Pod(填充
nodeName); - 节点上 kubelet 感知绑定后,拉取镜像、创建容器启动 Pod。
底层基于 Scheduling Framework(调度框架,1.19稳定) 插件化架构,所有调度逻辑拆分为可插拔插件,替代早期硬编码 Predicate/Priority。
2. 核心前置基础:组件通信流程
- kube-scheduler 通过
Informer长连接 Watch APIServer,缓存全量集群资源:Node、Pod、Service、ConfigMap、Taints/Tolerations、节点标签等; - 一旦创建无 nodeName 的 Pod,进入调度队列;
- 调度器执行筛选打分,成功后发起
Binding请求写入 APIServer; - APIServer 更新 Pod 对象写入 etcd;
- 对应节点 kubelet Watch 到本机 Pod,接管生命周期管理。
3. 调度整体五大阶段(Scheduling Framework 标准链路)
完整调度生命周期顺序:
QueueSort → PreFilter → Filter → PreScore → Score → Reserve → Permit → PreBind → Bind → PostBind
3.1. 阶段1:QueueSort 队列排序插件
作用:对调度队列里等待的 Pod 排序,决定调度先后顺序。
- 默认插件:
PrioritySort,依据 PodpriorityClassName数值排序,高优先级 Pod 先调度; - 自定义扩展:可实现自定义排队规则(离线任务延后、租户权重等)。
3.2. 阶段2:PreFilter 预过滤
对 Pod 做一次性前置校验,提前快速淘汰完全不满足条件的 Pod,避免遍历所有节点浪费性能。
常见校验逻辑:
- 校验 Pod 亲和/反亲和语法合法性;
- 校验拓扑分布约束参数;
- 资源配置合法性校验。
任意插件返回失败,Pod 直接退回调度队列重试。
3.3. 阶段3:Filter 预选阶段(原 Predicate)
硬性过滤,遍历所有节点,淘汰不满足条件的节点,留下候选节点列表。
所有 Filter 插件全部通过节点才保留,任一插件失败直接剔除节点。
内置核心 Filter 插件:
NodeResourcesFit:节点剩余 CPU/内存/GPU 满足 Pod requests;NodeTaintsTolerations:Pod 容忍节点所有污点;NodeAffinity:满足 Pod 硬节点亲和;PodAffinity:满足 Pod 硬亲和;PodAntiAffinity:满足 Pod 硬反亲和;PodTopologySpread:拓扑分布硬约束校验;NodePortFit:hostPort 不冲突;NodeReady:节点状态 Ready。
无候选节点时:Pod 标记调度失败,退回队列定时重试,事件输出 FailedScheduling。
3.4. 阶段4:PreScore 预打分
为后续打分插件做数据预处理、缓存计算,提升打分性能:
- 预统计各拓扑域 Pod 数量;
- 预加载节点标签、资源占用数据;
无淘汰逻辑,仅预处理。
3.5. 阶段5:Score 打分阶段(原 Priority)
对 Filter 输出的候选节点加权打分,总分越高优先级越高,选出最高分节点。
每个打分插件配置独立 weight 权重,分数区间 0~10。
核心内置打分插件:
LeastRequestedPriority(weight=10):节点已分配资源越少分数越高,均衡负载;BalancedResourceAllocation(weight=10):均衡 CPU/内存占用比例,避免单一资源打满;NodeAffinityPriority(weight=20):匹配软节点亲和加分;PodTopologySpread(weight=2):打散同标签 Pod,避免扎堆;TaintTolerationPriority:匹配更多容忍污点加分。
3.6. 阶段6:Reserve 资源预留
选中最优节点后,临时在调度器缓存标记预留资源,防止并发调度多个 Pod 抢占同一节点资源。
- 调度成功:保留预留;
- 后续绑定失败:释放预留资源。
3.7. 阶段7:Permit 许可插件(Gang调度核心)
阻塞 Pod 绑定,等待一组关联 Pod 全部调度完成才放行。
典型场景:Coscheduling(Gang 批量任务,Spark/AI 分布式训练),等待同任务所有 Pod 全部找到节点,再统一进入绑定阶段。
3.8. 阶段8:PreBind 绑定前预处理
执行绑定前自定义逻辑:
- 预创建 PVC 存储卷;
- 自定义资源申请;
预处理失败则取消 Reserve 资源预留,重新调度。
3.9. 阶段9:Bind 绑定(核心落盘动作)
唯一不可禁用的关键插件,执行真正绑定操作:
- 构造 Binding 对象,写入 Pod 名称、目标节点;
- 向 APIServer 发送绑定请求,更新 Pod
.spec.nodeName; - APIServer 校验:Pod 未被其他节点抢占,更新 etcd。
绑定是原子操作,并发调度冲突时会报错,触发重新调度。
3.10. 阶段10:PostBind 绑定后收尾
绑定完成后的后置逻辑,无调度阻断作用:
- 打印调度日志、上报监控指标;
- 清理临时缓存数据。
4. 抢占机制(Preemption):资源不足时高优Pod驱逐低优Pod
当 Filter 阶段无可用候选节点,但当前 Pod 为高优先级,触发抢占流程:
- 遍历所有节点,查找能腾出足够资源的节点;
- 在节点内筛选优先级更低的 Pod;
- 发送驱逐请求删除低优 Pod;
- 低优 Pod 进入重新调度队列;
- 低优 Pod 释放资源后,当前高优 Pod 完成调度绑定。
限制:同优先级 Pod 不会互相抢占;系统关键优先级 system-node-critical 不可被普通业务抢占。
5. 多调度 Profile 实现原理
单个 kube-scheduler 进程可加载多套独立调度插件配置(Profile):
- 每个 Profile 绑定唯一
schedulerName; - 各 Profile 插件完全隔离:A Profile 禁用的 Filter/Score 不影响其他 Profile;
- 共享同一套 Informer 缓存、领导者选举锁,相比多份独立 kube-scheduler 节省资源;
- Pod 通过
spec.schedulerName指定使用对应 Profile 的调度逻辑。
6. 领导者选举(高可用原理)
生产通常部署多副本 kube-scheduler 实现高可用,通过 Lease 锁保证同一时间只有一个活跃调度器:
- 锁资源:
kube-system/kube-schedulerLease 对象; - 抢到锁的实例成为主调度器,执行完整调度逻辑;
- 其余副本为备机,仅持续争抢锁,不处理 Pod;
- 主实例宕机、心跳超时,备机抢占锁接管调度,无单点故障。
7. 调度失败重试机制
Pod 调度失败(无节点、抢占失败、绑定冲突)不会永久阻塞:
- Pod 放回内部调度队列;
- 按照固定重试间隔重新执行完整调度链路;
- 同时在 Pod Events 持续打印失败原因(资源不足、亲和不匹配、污点不兼容等);
- 可通过调度器参数调整重试速率。
8. 与第三方调度器本质区别
- kube-scheduler(默认/多Profile):原生调度框架,插件扩展,复用集群原生缓存、抢占、绑定、领导者选举;适合微服务、在线业务轻量化定制。
- 独立调度器(Volcano/Koordinator/YuniKorn):独立二进制进程,独立 Informer、队列、抢占逻辑;适合批处理、AI混部、复杂多租户队列管控场景,通过 Pod
schedulerName分流调度。
9. 高频面试核心问答
- kube-scheduler 完整调度链路是什么?
QueueSort → PreFilter → Filter(预选) → PreScore → Score(打分) → Reserve → Permit → PreBind → Bind → PostBind。 - Filter 和 Score 核心区别?
Filter 是硬性过滤,不满足直接淘汰节点;Score 是加权打分,从合格节点选出最优。 - Permit 阶段作用?
用于 Gang 协同调度,阻塞 Pod,等待一批任务全部调度成功再绑定。 - 抢占机制触发条件?
无可用候选节点,且当前 Pod 优先级高于节点上已有 Pod,驱逐低优 Pod 释放资源。 - 多调度 Profile 底层依靠什么技术?
Scheduling Framework 插件化架构,单进程多套独立插件配置,通过 schedulerName 区分。 - 多副本 kube-scheduler 如何避免重复调度?
通过 kube-system 下 Lease 资源做领导者选举,仅抢到锁的实例执行调度。
10. 预选与打分速记
以下为预选与打分的简要总结,与上文完整链路搭配理解。
整体分为两大核心阶段:预选(Predicate)过滤节点 → 打分(Priority)择优节点
1. 预选阶段(过滤,淘汰不合格节点)
- 调度器拿到待调度 Pod,遍历集群所有节点;
- 依次执行一系列硬性过滤规则,任意一条不满足,直接剔除该节点;
- 仅留下全部规则通过的候选节点,进入打分环节;
- 无剩余候选节点时,Pod 持续 Pending,调度失败。
内置核心预选规则:
- PodFitsResources:节点剩余 CPU/内存 ≥ Pod 所有容器 requests 总和;
- PodFitsHostPorts:节点未占用 Pod 需要的 hostPort;
- NodeSelectorMatches:节点标签匹配 Pod nodeSelector;
- NodeAffinity:满足 Pod 节点亲和硬约束;
- PodToleratesNodeTaints:Pod 容忍节点所有污点;
- PodAntiAffinity:满足 Pod 反亲和硬打散约束;
- CheckNodeReady:节点状态正常 Ready。
2. 打分阶段(择优,给候选节点算分)
- 对预选筛选后的所有合格节点,执行多套打分算法,每项有固定权重;
- 各项分数加权求和,总分越高,调度优先级越高;
- 最终选择总分最高的节点绑定 Pod。
内置核心打分策略:
- LeastRequestedPriority(权重10):节点已分配资源越少分数越高,均衡负载;
- BalancedResourceAllocation(权重10):均衡节点 CPU、内存占用比例;
- NodeAffinityPriority(权重20):满足 Pod 软节点亲和的节点加分;
- TaintTolerationPriority:匹配容忍度高的节点加分;
- PodSpreadPriority:尽量打散同标签 Pod,避免扎堆。
3. 收尾绑定
选出最优节点后,调度器向 apiserver 提交绑定请求,写入 Pod 的 nodeName,完成调度。
关联文档
- Gang 调度(协同调度)完整详解 — Gang 协同调度
- K8s 多调度 Profile 完整配置教程 — 多 Profile 配置
- K8s 调度体系分类与主流调度器 — 调度生态总览
- K8s 高阶调度全解 — 亲和与污点调度