2、调度框架基础:Scheduling Framework 的 Plugin 机制、Queue、Cache、Scheduler Cycle

Kubernetes 调度器(kube-scheduler)在 v1.19 之后引入了 Scheduling Framework,将调度流程拆解为可插拔的扩展点。理解这一框架是排查调度一致性问题的前提。本节聚焦四个核心概念:Plugin 机制、调度队列(Queue)、调度缓存(Cache)以及调度周期(Scheduler Cycle)中的关键阶段。

2.1 Plugin 机制:可插拔的调度扩展点

Scheduling Framework 将调度流程抽象为多个扩展点(Extension Points),每个扩展点允许用户通过 Plugin 注入自定义逻辑。Plugin 通过 kube-scheduler --config 配置文件注册,支持多级评分与过滤。

扩展点 阶段 典型 Plugin 示例 作用
QueueSort 队列排序 PrioritySort 定义 Pod 在调度队列中的排序规则
PreFilter 预过滤 NodeResourcesFit 检查 Pod 是否满足集群基本资源条件
Filter 过滤 NodeName、TaintToleration 筛选出可调度节点(硬约束)
PostFilter 后过滤 DefaultPreemption 无可用节点时触发抢占
PreScore 预评分 NodeResourcesFit 为评分阶段准备节点信息
Score 评分 NodeResourcesBalancedAllocation 对过滤后的节点打分(软约束)
NormalizeScore 评分归一化 ImageLocality 将评分结果归一化到 [0,100]
Reserve 预留 VolumeBinding 在缓存中预留资源,防止并发冲突
Permit 许可 InterPodAffinity 等待外部条件或批准,支持超时与拒绝
PreBind 预绑定 NodeAffinity 绑定前执行准备工作
Bind 绑定 DefaultBinder 将 Pod 与 Node 绑定(写入 etcd)
PostBind 绑定后 NodeResourcesFit 绑定后清理或记录

关键理解:Plugin 的注册顺序影响调度结果。例如,NodeResourcesFit 同时出现在 Filter 和 Score 中,但 Filter 阶段先执行,Score 阶段后执行。若 Filter 阶段未通过,Score 阶段不会触发。

2.2 调度队列(Queue):Pod 的等待与排序

调度队列是 Pod 进入调度周期的第一站。kube-scheduler 内部维护三种队列:

  • activeQ:存放等待调度的 Pod,按 QueueSort Plugin 排序(默认按优先级)。
  • backoffQ:存放调度失败的 Pod,等待重试(指数退避)。
  • unschedulableQ:存放因节点资源不足或污点无法调度的 Pod,等待集群事件触发重新入队。

一致性排查要点:当集群资源变更(如节点新增、Pod 删除)后,检查 unschedulableQ 中的 Pod 是否被正确移动到 activeQ。若未移动,可能导致 Pod 长时间处于 Pending 状态。

2.3 调度缓存(Cache):节点状态的快照

调度缓存(SchedulerCache)是 kube-scheduler 内部维护的节点资源视图。它通过监听 API Server 的 Node、Pod 事件实时更新,但存在短暂的不一致窗口。

缓存组件 存储内容 更新方式
NodeInfo 节点资源总量、已分配资源、Pod 列表 Node/Pod 事件触发
PodInfo Pod 的请求资源、亲和性、污点容忍 Pod 事件触发
AssumedPod 已通过 Reserve 但未 Bind 的 Pod Reserve 阶段写入

风险提示:Cache 与 API Server 之间的数据不一致是调度一致性问题的主要来源。例如,Cache 中节点资源已更新,但 API Server 尚未同步,导致调度器做出错误决策。排查时需对比 kube-scheduler --v=5 日志中的 Cache 快照与 kubectl describe node 的输出。

2.4 Scheduler Cycle:Filter → Score → Reserve → Permit 核心流程

一个完整的调度周期(Scheduling Cycle)包含以下关键阶段。以下 SVG 展示了从 Pod 入队到绑定完成的完整流程。

调度周期核心流程(Scheduling Cycle) 调度队列 Filter 过滤 Score 评分 Reserve 预留 Permit 许可 Bind 绑定 失败回退队列 阶段说明: • Filter:硬约束检查,不通过直接进入失败回退队列。 • Score:对通过 Filter 的节点打分,选择最优节点。 • Reserve:在 Cache 中预留资源,防止并发调度冲突。 • Permit:等待外部条件(如资源配额、准入 Webhook),超时或拒绝则回退。

2.5 关键阶段详解:Filter、Score、Reserve、Permit

2.5.1 Filter(过滤)

Filter 阶段执行硬约束检查。所有 Filter Plugin 必须全部通过,Pod 才能进入下一阶段。常见的 Filter 包括:

  • NodeName:检查 Pod 是否指定了 spec.nodeName。
  • NodeUnschedulable:检查节点是否被标记为 unschedulable。
  • TaintToleration:检查 Pod 是否能容忍节点的污点。
  • NodeResourcesFit:检查节点剩余资源是否满足 Pod 请求。

2.5.2 Score(评分)

Score 阶段对通过 Filter 的节点进行打分,分数范围 [0, 100]。调度器选择总分最高的节点。常见评分策略:

  • NodeResourcesBalancedAllocation:优先选择资源分配更均衡的节点。
  • ImageLocality:优先选择已缓存所需镜像的节点。
  • InterPodAffinity:根据 Pod 亲和性/反亲和性打分。

2.5.3 Reserve(预留)

Reserve 阶段在调度缓存中为 Pod 预留资源。这是防止并发调度冲突的关键步骤。若 Reserve 失败(如资源已被其他 Pod 预留),调度器会回退并重试。

2.5.4 Permit(许可)

Permit 阶段允许外部条件控制调度是否继续。例如,等待资源配额批准或准入 Webhook 响应。Permit 支持三种结果:

  • 批准(Approved):继续执行 Bind。
  • 拒绝(Denied):Pod 进入失败回退队列。
  • 等待(Wait):Pod 进入等待状态,超时后自动拒绝。

一致性复核要点:在资源变更场景下,重点关注 Reserve 阶段是否成功更新 Cache。若 Reserve 成功但后续 Bind 失败,Cache 中的 AssumedPod 可能导致资源泄漏,需通过 kube-scheduler --v=5 日志中的 Cache after scheduling 信息进行校验。

2.6 调度周期与绑定周期的分离

Scheduling Framework 将调度周期(Scheduling Cycle)与绑定周期(Binding Cycle)分离。调度周期是串行的(同一时间只调度一个 Pod),而绑定周期是并发的。这种设计提高了吞吐量,但也引入了一致性风险:

  • 调度周期:Filter → Score → Reserve → Permit(串行,加锁)。
  • 绑定周期:PreBind → Bind → PostBind(并发,无锁)。

当绑定周期中的 Pod 因 API Server 延迟而长时间未完成 Bind 时,调度周期可能基于过时的 Cache 做出决策。这是资源变更后调度不一致的常见根因。

排查技巧:使用 kubectl get events --field-selector involvedObject.kind=Pod 查看 Pod 的调度事件。若出现 FailedScheduling 事件,结合 kube-scheduler --v=5 日志中的 Cache 和 Queue 状态,可快速定位是 Filter 失败还是 Reserve 冲突。