2. Kubernetes 调度基础:调度器核心组件、调度队列与调度周期
Kubernetes 调度器(kube-scheduler)是控制平面中负责将 Pod 绑定到合适 Node 的核心组件。理解其内部架构、调度队列机制以及两阶段调度周期,是进行调度优化与故障排查的前提。本章将深入剖析调度器的三大核心模块:Scheduler Framework、调度队列与调度周期。
2.1 调度器核心组件与 Scheduler Framework
Kubernetes 从 v1.19 开始将调度器重构为可插拔的 Scheduler Framework 架构。该框架定义了一组扩展点(Extension Points),允许用户通过编写插件(Plugin)来定制调度行为,而无需修改核心代码。
2.2 调度队列(Scheduling Queue)
调度队列是调度器的输入缓冲区,负责管理等待调度的 Pod。Kubernetes 使用优先级队列(Priority Queue)实现,Pod 按优先级排序,高优先级 Pod 优先出队。队列内部维护三个子队列:
| 子队列 | 存储内容 | 出队策略 | 典型场景 |
|---|---|---|---|
| ActiveQ | 等待首次调度的 Pod | 按优先级排序,高优先级先出队 | 新创建的 Pod |
| BackoffQ | 调度失败后进入退避的 Pod | 退避时间到期后移回 ActiveQ | 资源不足、节点污点不匹配 |
| UnschedulableQ | 因不可调度原因(如资源不足)失败的 Pod | 集群拓扑变化(如新节点加入)时重新评估 | 持久性资源不足、节点选择器不匹配 |
排查提示:当 Pod 长时间处于 Pending 状态时,可通过
kubectl describe pod <pod-name> 查看 Events 字段。若事件显示 "0/3 nodes are available",说明 Pod 进入了 UnschedulableQ。此时应检查节点资源水位或污点配置。
2.3 调度周期(Scheduling Cycle)与绑定周期(Binding Cycle)
调度器将每个 Pod 的调度过程拆分为两个独立的周期:调度周期和绑定周期。调度周期是串行的,绑定周期是并行的,这种设计显著提升了调度吞吐量。
2.3.1 调度周期(Scheduling Cycle)
调度周期是串行执行的,同一时间只有一个 Pod 处于调度周期中。它包含以下阶段:
- PreFilter:预处理 Pod 信息,检查 Pod 是否满足基本约束(如节点选择器、亲和性)。
- Filter:过滤节点,找出所有满足 Pod 资源请求和约束的候选节点。
- PostFilter:当 Filter 阶段没有找到可用节点时,执行干预逻辑(如抢占式调度)。
- PreScore:为 Score 阶段准备数据,如计算节点亲和性得分。
- Score:对候选节点进行打分,分数越高表示节点越适合运行该 Pod。
- NormalizeScore:对分数进行归一化处理,确保不同插件的分数在同一量级。
- Reserve:在调度器缓存中预留资源,防止并发调度导致资源冲突。
- Permit:允许或拒绝调度结果,支持等待/超时机制(如用于多调度器协调)。
2.3.2 绑定周期(Binding Cycle)
绑定周期是并行执行的,多个 Pod 可以同时处于绑定周期中。它包含以下阶段:
- PreBind:执行绑定前的准备工作,如动态创建存储卷(PV)。
- Bind:向 API Server 发送绑定请求,将 Pod 与 Node 关联。
- PostBind:绑定完成后的清理或通知逻辑。
性能关键点:调度周期是串行的,因此 Filter 和 Score 阶段的插件执行效率直接影响调度吞吐量。在生产环境中,建议将耗时较长的插件(如外部资源检查)放在 PreFilter 或 PreScore 阶段,避免阻塞整个调度周期。
2.4 调度器工作流程总结
以下表格总结了调度器从 Pod 入队到绑定完成的完整流程:
| 步骤 | 组件/阶段 | 操作 | 输出 |
|---|---|---|---|
| 1 | 调度队列 | Pod 进入 ActiveQ,按优先级排序 | 高优先级 Pod 出队 |
| 2 | 调度周期 | 执行 Filter → Score → Reserve → Permit | 选定目标 Node |
| 3 | 绑定周期 | 执行 PreBind → Bind → PostBind | Pod 与 Node 绑定 |
| 4 | 调度队列 | Pod 从队列中移除 | 调度完成 |
常见误区:调度周期中的 Reserve 阶段仅在调度器缓存中预留资源,并未实际写入 etcd。如果绑定周期失败,Reserve 阶段预留的资源会被释放。因此,不要将 Reserve 视为最终资源锁定。
2.5 调度器插件配置示例
以下是一个自定义调度器配置的 YAML 示例,展示了如何通过 Scheduler Framework 注册插件:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: custom-scheduler
plugins:
filter:
enabled:
- name: NodeResourcesFit
- name: NodeName
disabled:
- name: NodeUnschedulable
score:
enabled:
- name: NodeResourcesBalancedAllocation
weight: 2
- name: ImageLocality
weight: 1
pluginConfig:
- name: NodeResourcesBalancedAllocation
args:
resources:
- name: cpu
weight: 1
- name: memory
weight: 1
该配置定义了一个名为 custom-scheduler 的调度器,启用了自定义的 Filter 和 Score 插件,并禁用了默认的 NodeUnschedulable 过滤器。