Kubernetes

kube-scheduler 完整工作原理

·13 分钟阅读·4849 字
📋 目录

kube-scheduler 完整工作原理

1. 整体定位

kube-scheduler 是 Kubernetes 控制平面核心组件,负责为未绑定节点的 Pod 筛选最优节点。

  1. 监听 APIServer,持续获取 spec.nodeName=""(未调度)的 Pod;
  2. 依据节点资源、标签、亲和、污点、拓扑约束等规则筛选打分;
  3. 将最优节点绑定给 Pod(填充 nodeName);
  4. 节点上 kubelet 感知绑定后,拉取镜像、创建容器启动 Pod。

底层基于 Scheduling Framework(调度框架,1.19稳定) 插件化架构,所有调度逻辑拆分为可插拔插件,替代早期硬编码 Predicate/Priority。

2. 核心前置基础:组件通信流程

  1. kube-scheduler 通过 Informer 长连接 Watch APIServer,缓存全量集群资源:Node、Pod、Service、ConfigMap、Taints/Tolerations、节点标签等;
  2. 一旦创建无 nodeName 的 Pod,进入调度队列;
  3. 调度器执行筛选打分,成功后发起 Binding 请求写入 APIServer;
  4. APIServer 更新 Pod 对象写入 etcd;
  5. 对应节点 kubelet Watch 到本机 Pod,接管生命周期管理。

3. 调度整体五大阶段(Scheduling Framework 标准链路)

完整调度生命周期顺序:
QueueSort → PreFilter → Filter → PreScore → Score → Reserve → Permit → PreBind → Bind → PostBind

3.1. 阶段1:QueueSort 队列排序插件

作用:对调度队列里等待的 Pod 排序,决定调度先后顺序。

  • 默认插件:PrioritySort,依据 Pod priorityClassName 数值排序,高优先级 Pod 先调度;
  • 自定义扩展:可实现自定义排队规则(离线任务延后、租户权重等)。

3.2. 阶段2:PreFilter 预过滤

对 Pod 做一次性前置校验,提前快速淘汰完全不满足条件的 Pod,避免遍历所有节点浪费性能。
常见校验逻辑:

  • 校验 Pod 亲和/反亲和语法合法性;
  • 校验拓扑分布约束参数;
  • 资源配置合法性校验。
    任意插件返回失败,Pod 直接退回调度队列重试。

3.3. 阶段3:Filter 预选阶段(原 Predicate)

硬性过滤,遍历所有节点,淘汰不满足条件的节点,留下候选节点列表。
所有 Filter 插件全部通过节点才保留,任一插件失败直接剔除节点。
内置核心 Filter 插件:

  1. NodeResourcesFit:节点剩余 CPU/内存/GPU 满足 Pod requests;
  2. NodeTaintsTolerations:Pod 容忍节点所有污点;
  3. NodeAffinity:满足 Pod 硬节点亲和;
  4. PodAffinity:满足 Pod 硬亲和;
  5. PodAntiAffinity:满足 Pod 硬反亲和;
  6. PodTopologySpread:拓扑分布硬约束校验;
  7. NodePortFit:hostPort 不冲突;
  8. NodeReady:节点状态 Ready。

无候选节点时:Pod 标记调度失败,退回队列定时重试,事件输出 FailedScheduling

3.4. 阶段4:PreScore 预打分

为后续打分插件做数据预处理、缓存计算,提升打分性能:

  • 预统计各拓扑域 Pod 数量;
  • 预加载节点标签、资源占用数据;
    无淘汰逻辑,仅预处理。

3.5. 阶段5:Score 打分阶段(原 Priority)

对 Filter 输出的候选节点加权打分,总分越高优先级越高,选出最高分节点。
每个打分插件配置独立 weight 权重,分数区间 0~10。
核心内置打分插件:

  1. LeastRequestedPriority(weight=10):节点已分配资源越少分数越高,均衡负载;
  2. BalancedResourceAllocation(weight=10):均衡 CPU/内存占用比例,避免单一资源打满;
  3. NodeAffinityPriority(weight=20):匹配软节点亲和加分;
  4. PodTopologySpread(weight=2):打散同标签 Pod,避免扎堆;
  5. 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 绑定(核心落盘动作)

唯一不可禁用的关键插件,执行真正绑定操作:

  1. 构造 Binding 对象,写入 Pod 名称、目标节点;
  2. 向 APIServer 发送绑定请求,更新 Pod .spec.nodeName
  3. APIServer 校验:Pod 未被其他节点抢占,更新 etcd。

绑定是原子操作,并发调度冲突时会报错,触发重新调度。

3.10. 阶段10:PostBind 绑定后收尾

绑定完成后的后置逻辑,无调度阻断作用:

  • 打印调度日志、上报监控指标;
  • 清理临时缓存数据。

4. 抢占机制(Preemption):资源不足时高优Pod驱逐低优Pod

当 Filter 阶段无可用候选节点,但当前 Pod 为高优先级,触发抢占流程:

  1. 遍历所有节点,查找能腾出足够资源的节点;
  2. 在节点内筛选优先级更低的 Pod;
  3. 发送驱逐请求删除低优 Pod;
  4. 低优 Pod 进入重新调度队列;
  5. 低优 Pod 释放资源后,当前高优 Pod 完成调度绑定。

限制:同优先级 Pod 不会互相抢占;系统关键优先级 system-node-critical 不可被普通业务抢占。

5. 多调度 Profile 实现原理

单个 kube-scheduler 进程可加载多套独立调度插件配置(Profile):

  1. 每个 Profile 绑定唯一 schedulerName
  2. 各 Profile 插件完全隔离:A Profile 禁用的 Filter/Score 不影响其他 Profile;
  3. 共享同一套 Informer 缓存、领导者选举锁,相比多份独立 kube-scheduler 节省资源;
  4. Pod 通过 spec.schedulerName 指定使用对应 Profile 的调度逻辑。

6. 领导者选举(高可用原理)

生产通常部署多副本 kube-scheduler 实现高可用,通过 Lease 锁保证同一时间只有一个活跃调度器

  1. 锁资源:kube-system/kube-scheduler Lease 对象;
  2. 抢到锁的实例成为主调度器,执行完整调度逻辑;
  3. 其余副本为备机,仅持续争抢锁,不处理 Pod;
  4. 主实例宕机、心跳超时,备机抢占锁接管调度,无单点故障。

7. 调度失败重试机制

Pod 调度失败(无节点、抢占失败、绑定冲突)不会永久阻塞:

  1. Pod 放回内部调度队列;
  2. 按照固定重试间隔重新执行完整调度链路;
  3. 同时在 Pod Events 持续打印失败原因(资源不足、亲和不匹配、污点不兼容等);
  4. 可通过调度器参数调整重试速率。

8. 与第三方调度器本质区别

  1. kube-scheduler(默认/多Profile):原生调度框架,插件扩展,复用集群原生缓存、抢占、绑定、领导者选举;适合微服务、在线业务轻量化定制。
  2. 独立调度器(Volcano/Koordinator/YuniKorn):独立二进制进程,独立 Informer、队列、抢占逻辑;适合批处理、AI混部、复杂多租户队列管控场景,通过 Pod schedulerName 分流调度。

9. 高频面试核心问答

  1. kube-scheduler 完整调度链路是什么?
    QueueSort → PreFilter → Filter(预选) → PreScore → Score(打分) → Reserve → Permit → PreBind → Bind → PostBind。
  2. Filter 和 Score 核心区别?
    Filter 是硬性过滤,不满足直接淘汰节点;Score 是加权打分,从合格节点选出最优。
  3. Permit 阶段作用?
    用于 Gang 协同调度,阻塞 Pod,等待一批任务全部调度成功再绑定。
  4. 抢占机制触发条件?
    无可用候选节点,且当前 Pod 优先级高于节点上已有 Pod,驱逐低优 Pod 释放资源。
  5. 多调度 Profile 底层依靠什么技术?
    Scheduling Framework 插件化架构,单进程多套独立插件配置,通过 schedulerName 区分。
  6. 多副本 kube-scheduler 如何避免重复调度?
    通过 kube-system 下 Lease 资源做领导者选举,仅抢到锁的实例执行调度。

10. 预选与打分速记

以下为预选与打分的简要总结,与上文完整链路搭配理解。

整体分为两大核心阶段:预选(Predicate)过滤节点 → 打分(Priority)择优节点

1. 预选阶段(过滤,淘汰不合格节点)

  1. 调度器拿到待调度 Pod,遍历集群所有节点;
  2. 依次执行一系列硬性过滤规则,任意一条不满足,直接剔除该节点;
  3. 仅留下全部规则通过的候选节点,进入打分环节;
  4. 无剩余候选节点时,Pod 持续 Pending,调度失败。

内置核心预选规则:

  1. PodFitsResources:节点剩余 CPU/内存 ≥ Pod 所有容器 requests 总和;
  2. PodFitsHostPorts:节点未占用 Pod 需要的 hostPort;
  3. NodeSelectorMatches:节点标签匹配 Pod nodeSelector;
  4. NodeAffinity:满足 Pod 节点亲和硬约束;
  5. PodToleratesNodeTaints:Pod 容忍节点所有污点;
  6. PodAntiAffinity:满足 Pod 反亲和硬打散约束;
  7. CheckNodeReady:节点状态正常 Ready。

2. 打分阶段(择优,给候选节点算分)

  1. 对预选筛选后的所有合格节点,执行多套打分算法,每项有固定权重;
  2. 各项分数加权求和,总分越高,调度优先级越高;
  3. 最终选择总分最高的节点绑定 Pod。

内置核心打分策略:

  1. LeastRequestedPriority(权重10):节点已分配资源越少分数越高,均衡负载;
  2. BalancedResourceAllocation(权重10):均衡节点 CPU、内存占用比例;
  3. NodeAffinityPriority(权重20):满足 Pod 软节点亲和的节点加分;
  4. TaintTolerationPriority:匹配容忍度高的节点加分;
  5. PodSpreadPriority:尽量打散同标签 Pod,避免扎堆。

3. 收尾绑定

选出最优节点后,调度器向 apiserver 提交绑定请求,写入 Pod 的 nodeName,完成调度。

关联文档