调度框架(Scheduling Framework)设计理念与扩展点详解

Kubernetes 调度器从 v1.19 开始引入了 Scheduling Framework(调度框架),这是一套插件化的调度架构。它将调度流程拆解为多个明确定义的阶段(Phase),每个阶段都开放了扩展点(Extension Point),允许开发者通过编写插件来注入自定义调度逻辑,而无需修改调度器核心代码。

设计理念:调度框架的核心思想是“流程固定、逻辑可插拔”。调度器负责编排扩展点的执行顺序,插件负责实现具体的调度策略。这种设计极大提升了调度器的可扩展性和可维护性。

2.1 调度框架的核心设计理念

调度框架的设计围绕以下三个核心理念展开:

  • 阶段化(Phasing):将调度周期(Scheduling Cycle)和绑定周期(Binding Cycle)拆分为多个顺序执行的阶段,每个阶段职责单一。
  • 插件化(Plugin):每个扩展点可以注册多个插件,插件之间通过优先级排序,按序执行。
  • 可组合(Composable):用户可以根据集群需求,通过 KubeSchedulerConfiguration 配置文件灵活组合插件,实现定制化调度行为。

调度框架将一次 Pod 调度过程分为两个主要周期:

周期 说明 包含扩展点
Scheduling Cycle 为 Pod 选择一个合适的 Node,该过程在调度器内部串行执行 QueueSort、PreFilter、Filter、PostFilter、PreScore、Score、NormalizeScore、Reserve、Permit
Binding Cycle 将 Pod 绑定到选定的 Node,该过程可异步执行 PreBind、Bind、PostBind
关键理解:Scheduling Cycle 是同步的,确保同一时间只有一个 Pod 进入调度决策;Binding Cycle 是异步的,允许绑定操作并发执行,提升吞吐量。

2.2 调度框架整体流程(SVG)

下图展示了调度框架中 Scheduling Cycle 与 Binding Cycle 的完整流程,以及各扩展点的执行顺序:

调度框架扩展点流程 调度框架(Scheduling Framework)扩展点流程 Scheduling Cycle(调度周期)— 串行执行 QueueSort PreFilter Filter PostFilter PreScore Score NormalizeScore Reserve Permit Binding Cycle(绑定周期)— 可异步执行 PreBind Bind PostBind 说明: • Scheduling Cycle 中,Filter 和 Score 是最常用的扩展点,分别用于节点过滤和打分。 • Permit 扩展点支持“等待批准”机制,可用于实现容量调度、优先级抢占等高级策略。 • Bind 扩展点通常只有一个插件生效(默认是 DefaultBinder),负责将 Pod 绑定到 Node。

2.3 扩展点详解

调度框架共定义了 11 个扩展点,分布在调度周期和绑定周期中。每个扩展点都有明确的输入、输出和职责。

2.3.1 Scheduling Cycle 扩展点

扩展点 执行时机 核心职责 典型插件示例
QueueSort 调度队列排序时 对等待调度的 Pod 进行排序,决定出队顺序 PrioritySort
PreFilter Filter 之前 预处理 Pod 信息,检查 Pod 是否满足调度前提条件 NodeResourcesFit、PodTopologySpread
Filter 节点过滤阶段 过滤掉不满足 Pod 调度要求的节点 NodeResourcesFit、NodeName、NodeUnschedulable
PostFilter Filter 之后,无可用节点时 处理调度失败场景,如抢占、备用节点推荐 Preemption、DefaultPreemption
PreScore Score 之前 为打分阶段准备数据,如计算拓扑分布信息 PodTopologySpread
Score 节点打分阶段 对通过 Filter 的节点进行打分,分值越高越优先 NodeResourcesFit、ImageLocality
NormalizeScore Score 之后 对多个 Score 插件的打分结果进行归一化处理 NodeResourcesFit
Reserve 选定节点后,绑定前 在调度器缓存中预留 Pod 资源,防止并发冲突 NodeResourcesFit
Permit Reserve 之后,绑定前 批准或拒绝 Pod 调度,支持等待/超时机制 默认允许、自定义准入控制

2.3.2 Binding Cycle 扩展点

扩展点 执行时机 核心职责 典型插件示例
PreBind 绑定之前 执行绑定前的准备工作,如创建存储卷、网络资源 VolumeBinding
Bind 绑定阶段 将 Pod 与 Node 的绑定关系写入 API Server DefaultBinder
PostBind 绑定之后 绑定成功后的清理或通知操作 无默认实现
注意:Bind 扩展点比较特殊,调度框架允许多个 Bind 插件共存,但最终只有一个插件会执行实际的绑定操作(通常按优先级选择)。如果所有 Bind 插件都跳过,调度器会使用默认的 DefaultBinder。

2.4 扩展点执行顺序与插件优先级

调度框架通过 KubeSchedulerConfiguration 中的 plugins 字段来配置每个扩展点启用的插件及其执行顺序。每个插件可以设置 weight(权重)和 order(顺序)。

以下是一个典型的调度器配置片段:

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
  - schedulerName: default-scheduler
    plugins:
      filter:
        enabled:
          - name: NodeResourcesFit
          - name: NodeName
          - name: NodeUnschedulable
        disabled:
          - name: "*"   # 禁用所有默认 Filter 插件,仅保留上面启用的
      score:
        enabled:
          - name: NodeResourcesFit
            weight: 2
          - name: ImageLocality
            weight: 1
      permit:
        enabled:
          - name: CustomPermitPlugin
    pluginConfig:
      - name: NodeResourcesFit
        args:
          scoringStrategy:
            type: LeastAllocated   # 使用最少资源分配策略
实践建议:在配置插件时,建议先了解每个扩展点的默认插件列表。使用 disabled: ["*"] 会清空该扩展点的所有默认插件,需谨慎操作。推荐采用“增量式”配置,即只添加或禁用特定插件,保留其他默认插件。

2.5 扩展点与节点资源碎片治理的关系

在节点资源碎片治理场景中,调度框架的以下扩展点尤为关键:

  • Filter 扩展点:通过 NodeResourcesFit 插件过滤掉资源碎片严重的节点,避免将 Pod 调度到剩余资源零散、无法容纳新 Pod 的节点。
  • Score 扩展点:通过自定义打分策略(如 MostAllocated 或 LeastAllocated)引导 Pod 优先调度到资源利用率高或碎片程度低的节点。
  • PreFilter 扩展点:在调度前检查 Pod 的资源需求,提前排除明显不满足条件的节点,减少后续 Filter 的计算开销。
  • Reserve 扩展点:确保在并发调度场景下,资源预留不会导致碎片加剧。

通过合理配置这些扩展点的插件,调度器可以在调度决策中主动考虑节点资源碎片因素,从而提升集群整体资源利用率。

2.6 扩展点插件开发接口

调度框架为每个扩展点定义了 Go 接口,开发者只需实现对应接口即可注册为插件。以下是最常用的两个扩展点接口示例:

// FilterPlugin 接口
type FilterPlugin interface {
    Plugin
    Filter(ctx context.Context, state *CycleState, pod *v1.Pod, nodeInfo *NodeInfo) *Status
}

// ScorePlugin 接口
type ScorePlugin interface {
    Plugin
    Score(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) (int64, *Status)
    ScoreExtensions() ScoreExtensions
}
开发提示:编写自定义插件时,建议使用 framework.Handle 接口访问调度器缓存、客户端等基础设施。插件注册后,需要在 KubeSchedulerConfiguration 中显式启用才能生效。

2.7 调度框架的优势总结

特性 传统调度器 调度框架
扩展方式 修改核心代码、重新编译 编写插件、动态配置
调度流程 硬编码、难以定制 阶段化、可插拔
并发模型 串行调度 调度周期串行 + 绑定周期异步
配置灵活性 通过命令行参数调整 通过 API 配置精细控制
社区生态 官方插件有限 丰富的内置插件 + 自定义插件