2. Kubernetes 调度基础:调度器工作原理、调度框架、调度队列与调度周期

Kubernetes 调度器(kube-scheduler)是控制平面中负责将 Pod 绑定到合适 Node 的核心组件。理解其内部工作原理、可扩展的调度框架、调度队列机制以及完整的调度周期,是进行调度优化和实现多租户发布窗口隔离的理论基础。

2.1 调度器工作原理概述

kube-scheduler 作为一个独立的二进制进程运行,通过 Kubernetes API 监听(Watch)未调度的 Pod(即 spec.nodeName 为空),并为每个待调度 Pod 选择一个最优的 Node,然后将绑定结果写入 API Server。其核心工作流程遵循“过滤 → 打分 → 绑定”的三段式模型。

核心职责: 为每个新创建的、尚未分配到节点的 Pod,从集群中所有可用的 Node 中,选择一个最合适的节点运行它。
阶段 名称 描述 关键动作
1 过滤(Predicates / Filtering) 遍历所有 Node,排除不满足 Pod 调度约束的节点。 检查资源充足性、端口冲突、节点选择器、亲和性规则等。
2 打分(Priorities / Scoring) 对通过过滤的 Node 进行优先级评分,选出最优节点。 计算资源利用率、Pod 分布均衡性、亲和性权重等。
3 绑定(Binding) 将 Pod 与选定的 Node 进行绑定,更新 API Server 中的 Pod 对象。 创建 Binding 对象,更新 spec.nodeName。
调度器三段式工作流程 1. 过滤阶段 Predicates 2. 打分阶段 Priorities 3. 绑定阶段 Binding 输入:未调度 Pod → 过滤出候选节点 → 打分选出最优节点 → 输出:Pod 与 Node 的绑定关系

2.2 调度框架(Scheduling Framework)

从 Kubernetes v1.19 开始,调度器引入了可插拔的调度框架。该框架定义了一组扩展点(Extension Points),允许开发者通过编写调度插件(Plugin)来定制调度行为,而无需修改调度器核心代码。这是实现自定义调度策略(如租户感知调度、窗口隔离调度)的关键机制。

2.2.1 核心扩展点

调度框架在调度周期的不同阶段插入了多个扩展点。插件可以在一个或多个扩展点注册并执行逻辑。

扩展点 所属阶段 插件作用 典型用例
QueueSort 调度队列 对调度队列中的 Pod 进行排序。 实现优先级抢占、租户公平排队。
PreFilter 过滤前 预处理 Pod 信息,检查 Pod 是否满足调度前提条件。 验证 Pod 的卷、网络等前置依赖。
Filter 过滤 排除不满足条件的 Node。 节点资源检查、污点容忍、节点亲和性。
PostFilter 过滤后 当过滤阶段没有可用 Node 时执行,通常用于抢占。 低优先级 Pod 抢占高优先级 Pod 的资源。
PreScore 打分前 生成可共享的打分状态数据。 计算全局资源视图。
Score 打分 对每个 Node 进行评分(0-100)。 资源均衡、镜像本地性、亲和性权重。
NormalizeScore 打分后 对多个 Score 插件的评分结果进行修正或组合。 权重归一化。
Reserve 绑定前 在选定 Node 上预留资源,防止并发冲突。 确保资源原子性分配。
Permit 绑定前 批准或延迟 Pod 的绑定,实现门控机制。 发布窗口隔离:在窗口外延迟绑定。
PreBind 绑定 在正式绑定前执行预处理。 挂载网络卷、配置网络策略。
Bind 绑定 执行最终的 Pod 与 Node 绑定操作。 默认绑定器或自定义绑定逻辑。
调度框架扩展点与调度周期 QueueSort PreFilter Filter Score Permit Bind Pod 排队与排序(支持自定义优先级队列) 预处理 Pod 信息,检查前置条件 过滤不可用节点(资源、污点、亲和性) 对候选节点进行打分(0-100) 批准/延迟/拒绝绑定(发布窗口隔离关键点) 执行 Pod 与 Node 的绑定操作
关键洞察: Permit 扩展点是实现“发布窗口隔离”的核心位置。通过编写一个 Permit 插件,可以检查当前时间是否在租户允许的发布窗口内,如果不在,则返回 Wait 状态,将 Pod 挂起,直到窗口打开或超时。

2.3 调度队列(Scheduling Queue)

调度队列是调度器的输入缓冲区,负责管理所有等待调度的 Pod。调度器并非为每个 Pod 立即启动一个调度周期,而是将 Pod 放入队列中,按特定顺序取出处理。队列的管理直接影响调度的公平性和效率。

2.3.1 队列类型与结构

调度器内部维护了三种逻辑队列:

  • ActiveQ(活跃队列): 存放所有准备好被调度的 Pod。调度器的主循环从这个队列中取出 Pod 进行处理。
  • BackoffQ(回退队列): 存放调度失败的 Pod。这些 Pod 在等待一段时间(回退时间)后,会被重新放回 ActiveQ 重试。
  • UnschedulableQ(不可调度队列): 存放因集群资源不足或节点不匹配而无法调度的 Pod。当集群拓扑发生变化(如新增节点、资源释放)时,这些 Pod 会被重新评估并移回 ActiveQ。
队列名称 存储对象 触发重新入队条件 作用
ActiveQ 等待调度的 Pod Pod 被创建、BackoffQ 超时、UnschedulableQ 触发事件 主调度循环的输入源
BackoffQ 调度失败的 Pod 回退计时器到期(指数退避) 避免频繁重试导致调度器过载
UnschedulableQ 因资源不足无法调度的 Pod 集群事件(新增 Node、删除 Pod、资源更新) 避免无效轮询,仅在集群状态变化时重试

2.3.2 队列排序与优先级

ActiveQ 默认是一个基于堆(Heap)实现的优先级队列。Pod 的排序规则由 QueueSort 扩展点插件决定。默认的排序策略基于 Pod 的优先级(Priority)和创建时间戳。高优先级的 Pod 会排在前面,相同优先级下,创建时间更早的 Pod 优先。

多租户场景注意: 默认的优先级排序可能导致某个租户的大量高优先级 Pod 持续占用调度资源,造成“租户饿死”。在生产环境中,建议通过自定义 QueueSort 插件实现基于租户的公平调度(如轮询、加权公平队列),确保每个租户在调度队列中都有机会被处理。

2.4 调度周期(Scheduling Cycle)

一个完整的调度周期是指调度器从 ActiveQ 中取出一个 Pod 开始,到成功绑定或决定放弃该 Pod 为止的完整过程。它由多个阶段组成,并严格遵循调度框架定义的扩展点顺序。

2.4.1 调度周期阶段详解

  1. 出队: 从 ActiveQ 中取出优先级最高的 Pod。
  2. PreFilter: 执行 PreFilter 插件,进行前置检查(如 Pod 是否已被调度、卷是否就绪)。
  3. Filter: 执行 Filter 插件,遍历所有 Node,生成候选节点列表。如果候选节点为空,则进入 PostFilter(抢占逻辑)或将 Pod 放入 UnschedulableQ。
  4. PreScore/Score/NormalizeScore: 对候选节点进行打分和归一化,选出得分最高的节点。
  5. Reserve: 在选定节点上预留资源,防止并发调度冲突。
  6. Permit: 执行 Permit 插件。如果所有 Permit 插件都批准,则继续;如果有插件返回 Wait,则 Pod 进入等待状态,直到被批准或超时。
  7. PreBind/Bind: 执行绑定前的预处理(如挂载卷),然后执行 Bind 插件将 Pod 绑定到 Node。
  8. PostBind: 绑定成功后执行清理或通知操作。
调度周期完整流程(含队列交互) ActiveQ 优先级队列 出队 Filter Score Permit Bind 调度失败 → BackoffQ / UnschedulableQ Permit 等待 → 挂起直到窗口打开或超时 调度周期是原子操作:一个 Pod 的调度周期结束后,调度器才会从 ActiveQ 中取出下一个 Pod 进行处理

2.5 调度器配置与多调度器

Kubernetes 支持在一个集群中运行多个调度器实例。Pod 可以通过 spec.schedulerName 字段指定使用哪个调度器。默认调度器的名称为 default-scheduler。

# Pod 指定使用自定义调度器
apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  schedulerName: my-custom-scheduler  # 指定调度器名称
  containers:
  - name: my-container
    image: nginx
实践建议: 对于多租户场景,可以为每个租户或每组租户部署独立的调度器实例,并配置不同的调度策略(如不同的 Filter/Score 插件、不同的队列排序规则)。这可以实现物理级别的调度隔离,避免一个租户的调度行为影响另一个租户。

2.6 本章小结

  • 调度器工作原理 遵循“过滤 → 打分 → 绑定”的三段式模型,核心是找到满足约束的最优节点。
  • 调度框架 提供了可插拔的扩展点,特别是 Permit 扩展点,是实现发布窗口隔离的关键技术。
  • 调度队列 管理 Pod 的排队和重试逻辑,通过自定义 QueueSort 插件可以实现租户间的公平调度。
  • 调度周期 是一个完整的、原子性的处理流程,理解其内部阶段有助于定位调度瓶颈和设计自定义插件。