2. 调度器核心组件解析:调度队列、调度框架与调度/绑定周期
Kubernetes 调度器(kube-scheduler)的核心职责是为待调度的 Pod 找到最合适的节点。这一过程由三大核心组件协同完成:调度队列(Scheduling Queue)负责管理待调度 Pod 的优先级与顺序;调度框架(Scheduling Framework)提供可扩展的插件化调度管线;调度周期与绑定周期则定义了从“选节点”到“写绑定”的完整生命周期。
2.1 调度队列(Scheduling Queue)
调度队列是调度器的“输入缓冲区”,负责接收、排序和去重待调度的 Pod。Kubernetes 默认使用 PriorityQueue 实现,内部维护三个子队列:
| 队列名称 | 存储内容 | 出队顺序 | 典型场景 |
|---|---|---|---|
| activeQ | 可立即调度的 Pod | 按优先级(Priority)降序,同优先级按入队时间 | 新创建的 Pod、重试的 Pod |
| backoffQ | 调度失败且处于退避期的 Pod | 退避时间到期后移至 activeQ | 因资源不足、污点不匹配等临时失败 |
| unschedulableQ | 因集群状态变化可能可调度的 Pod | 收到 Node/CSI/PV 变更事件后重新评估 | 因节点不可用、存储不可达等结构性原因失败 |
关键指标:调度队列深度(
scheduler_queue_incoming_pods_total)和 Pod 在队列中的等待时间(scheduler_pod_queue_duration_seconds)是排查调度延迟的首要监控指标。
调度队列的入队与出队逻辑遵循以下步骤:
- 入队:Pod 通过 Informer 机制监听 API Server,新 Pod 或更新后的 Pod 被加入 activeQ。
- 排序:activeQ 使用最小堆(heap)实现,比较函数优先检查 Pod 的
spec.priority,再比较creationTimestamp。 - 出队:调度主循环调用
NextPod()从 activeQ 取出优先级最高的 Pod。 - 回退:调度失败后,根据失败次数计算退避时间(指数退避,最大 10 秒),放入 backoffQ。
- 重试:集群资源变更时,unschedulableQ 中的 Pod 被批量移回 activeQ 或 backoffQ。
避坑指南:如果大量高优先级 Pod 持续涌入,低优先级 Pod 可能长期滞留在队列中(饥饿问题)。建议配合 Pod Priority Preemption 和 调度框架的 QueueSort 插件 进行公平性调优。
2.2 调度框架(Scheduling Framework)
调度框架是 Kubernetes 1.19+ 引入的插件化调度管线,它将调度过程拆解为多个可扩展的扩展点(Extension Points)。每个扩展点允许用户注册自定义插件,实现调度策略的灵活定制。
调度框架的核心设计原则包括:
- 插件化:每个扩展点可注册多个插件,插件按顺序执行,任一插件返回失败则终止当前周期。
- 可组合:用户可通过
KubeSchedulerConfiguration配置文件启用/禁用/排序插件,无需修改调度器代码。 - 状态共享:插件可通过
CycleState在调度周期内传递数据,避免重复计算。
实践案例:网络拓扑感知调度可通过实现 Score 扩展点 的插件,读取节点拓扑标签(如
topology.kubernetes.io/zone),为同可用区的节点赋予更高分数,从而减少跨 AZ 流量。
2.3 调度周期与绑定周期
调度器将一个 Pod 的完整调度过程分为两个阶段:调度周期(Scheduling Cycle) 和 绑定周期(Binding Cycle)。调度周期是串行的,绑定周期是并行的,两者通过 Permit 扩展点 衔接。
| 阶段 | 执行顺序 | 是否阻塞 | 核心扩展点 | 输出 |
|---|---|---|---|---|
| 调度周期 | 串行(一次一个 Pod) | 是 | QueueSort → PreFilter → Filter → PostFilter → PreScore → Score → NormalizeScore → Reserve | 选中的节点名称 |
| 绑定周期 | 并行(多个 Pod 可同时绑定) | 否 | Permit → PreBind → Bind → PostBind | Pod 与节点的绑定关系写入 API Server |
重要区别:调度周期是“选节点”,绑定周期是“写绑定”。调度周期失败不会影响其他 Pod,绑定周期失败可能导致 Pod 处于“已预留但未绑定”的中间状态,需要 Unreserve 插件 清理预留资源。
调度周期与绑定周期的完整交互流程如下:
- 出队:调度主循环从 activeQ 取出一个 Pod,进入调度周期。
- 过滤与打分:依次执行 PreFilter、Filter、PostFilter(可选)、PreScore、Score、NormalizeScore,选出最优节点。
- 预留:Reserve 插件在选中的节点上预留资源(如 CSI 卷挂载点),防止并发调度冲突。
- 许可:Permit 插件决定是否允许进入绑定周期(可设置超时或等待依赖)。
- 绑定:PreBind 执行前置操作(如动态创建 PV),Bind 将 Pod 的
spec.nodeName写入 API Server,PostBind 执行后置清理。 - 异步等待:绑定周期完成后,调度器继续处理下一个 Pod,kubelet 监听到绑定事件后启动 Pod。
性能优化:调度周期串行执行保证了节点选择的原子性,避免两个 Pod 同时选中同一节点导致资源冲突。绑定周期并行执行则充分利用了 API Server 的并发写入能力,显著提升大规模集群的调度吞吐量。
2.4 核心组件协作总结
调度队列、调度框架、调度/绑定周期三者协作关系如下:
- 调度队列 提供有序的 Pod 输入流,确保高优先级 Pod 优先被处理。
- 调度框架 将调度过程拆解为可插拔的扩展点,允许用户自定义过滤、打分、绑定逻辑。
- 调度周期 负责串行选节点,绑定周期 负责并行写绑定,两者通过 Permit 扩展点解耦。
理解这三个核心组件是掌握 Kubernetes 调度器架构的基础,也是后续实现网络拓扑感知调度、自定义调度插件开发的必备知识。