3. 调度框架(Scheduling Framework)总览:扩展点(Extension Points)与插件机制
Kubernetes 调度器从 v1.19 开始引入了 Scheduling Framework,将调度流程拆解为多个明确定义的阶段,每个阶段称为一个 扩展点(Extension Point)。用户可以通过实现插件(Plugin)接口,在特定扩展点注入自定义逻辑,从而在不修改核心代码的前提下深度定制调度行为。
3.1 调度框架的核心设计理念
传统调度器采用硬编码的“Predicates + Priorities”两阶段模型,扩展性差、维护成本高。Scheduling Framework 将调度流程拆解为多个可插拔的扩展点,每个扩展点对应一个明确的调度阶段,插件可以注册到任意一个或多个扩展点。
核心优势:
- 解耦:调度逻辑与核心框架分离,插件独立开发、独立部署。
- 可组合:多个插件可以注册到同一扩展点,按优先级顺序执行。
- 可观测:每个扩展点都有明确的输入/输出,便于监控和调试。
- 标准化:插件接口(Plugin API)统一,降低开发门槛。
3.2 扩展点全景图
调度框架定义了 11 个核心扩展点,分布在调度周期的不同阶段。下图展示了扩展点的完整流程及其与调度周期的对应关系:
3.3 扩展点详解
每个扩展点都有明确的职责和接口定义。下表总结了所有扩展点的功能、触发时机和典型用途:
| 扩展点 | 阶段 | 功能描述 | 典型用途 |
|---|---|---|---|
| QueueSort | 排序 | 对调度队列中的 Pod 进行排序,决定下一个调度的 Pod | 实现自定义优先级排序策略 |
| PreFilter | 预过滤 | 在 Filter 之前执行,用于预处理或校验 Pod 信息 | 检查 Pod 的拓扑分布约束、资源预留 |
| Filter | 过滤 | 对每个节点执行过滤,排除不满足条件的节点 | 节点资源检查、端口冲突、污点容忍 |
| PostFilter | 后过滤 | 当 Filter 阶段没有可用节点时执行,尝试替代方案 | 抢占(Preemption)、节点扩展 |
| PreScore | 预评分 | 在 Score 之前执行,用于生成评分所需的共享数据 | 计算节点间的拓扑距离、网络延迟矩阵 |
| Score | 评分 | 对通过 Filter 的节点进行评分,分值越高越优先 | 资源利用率、亲和性、网络拓扑感知 |
| NormalizeScore | 归一化 | 对多个 Score 插件的评分结果进行归一化处理 | 将不同量纲的评分统一到 [0, 100] 区间 |
| Reserve | 预留 | 在节点上预留资源,确保后续绑定成功 | 资源锁定、避免竞态条件 |
| Permit | 许可 | 批准或延迟 Pod 的调度决策,支持等待/拒绝 | 多租户配额、跨集群调度协调 |
| PreBind | 预绑定 | 在正式绑定前执行,用于准备绑定所需的资源 | 动态创建存储卷、网络配置 |
| Bind | 绑定 | 将 Pod 绑定到选定节点,写入 etcd | 默认绑定、自定义绑定逻辑 |
| PostBind | 后绑定 | 绑定完成后执行,用于清理或通知 | 日志记录、监控指标上报 |
3.4 插件机制与生命周期
插件是 Scheduling Framework 的核心扩展单元。每个插件需要实现一个或多个扩展点接口,并通过配置文件注册到调度器中。
3.4.1 插件接口定义
每个扩展点对应一个 Go 接口,插件通过实现这些接口来注入逻辑。以 Filter 扩展点为例:
// FilterPlugin 接口定义
type FilterPlugin interface {
Plugin
// Filter 在调度周期中为每个节点调用
// 返回 Success 表示节点可用,Unschedulable 表示不可用
Filter(ctx context.Context, state *CycleState, pod *v1.Pod, nodeInfo *NodeInfo) *Status
}
// ScorePlugin 接口定义
type ScorePlugin interface {
Plugin
// Score 为每个节点打分,分值范围 [0, MaxScore]
Score(ctx context.Context, state *CycleState, pod *v1.Pod, nodeName string) (int64, *Status)
// ScoreExtensions 返回归一化扩展(可选)
ScoreExtensions() ScoreExtensions
}
3.4.2 插件注册与配置
插件通过 KubeSchedulerConfiguration 配置文件注册。以下示例展示了如何注册一个自定义的拓扑感知插件:
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: topology-aware-scheduler
plugins:
# 在 Filter 扩展点注册拓扑过滤插件
filter:
enabled:
- name: TopologyFilter
weight: 1
# 在 Score 扩展点注册拓扑评分插件
score:
enabled:
- name: TopologyScore
weight: 3
# 在 Reserve 扩展点注册资源预留插件
reserve:
enabled:
- name: TopologyReserve
pluginConfig:
- name: TopologyFilter
args:
topologyKey: "topology.kubernetes.io/zone"
- name: TopologyScore
args:
bandwidthWeight: 0.7
latencyWeight: 0.3
3.5 插件执行顺序与权重
多个插件可以注册到同一个扩展点,调度框架按照以下规则决定执行顺序:
- 内置插件优先:Kubernetes 内置插件(如 NodeResourcesFit、NodeAffinity)默认排在用户自定义插件之前。
- 权重排序:对于 Score 扩展点,插件的权重(weight)影响最终评分占比。
- 配置顺序:在配置文件中,enabled 列表的顺序决定了插件的执行顺序。
最佳实践:在开发自定义插件时,建议先实现 Filter 扩展点进行节点筛选,再实现 Score 扩展点进行精细化评分。对于网络拓扑感知场景,PreScore 扩展点非常适合预计算节点间的网络距离矩阵,避免在 Score 阶段重复计算。
3.6 扩展点与网络拓扑感知的关联
在容器网络拓扑感知调度场景中,以下扩展点最为关键:
| 扩展点 | 网络拓扑感知中的作用 |
|---|---|
| PreFilter | 解析 Pod 的网络拓扑约束(如必须部署在同一可用区) |
| Filter | 排除不满足网络连通性要求的节点(如跨区域延迟过高) |
| PreScore | 预计算节点间的网络距离矩阵、带宽可用性 |
| Score | 根据网络拓扑距离、带宽、延迟等指标对节点评分 |
| Reserve | 预留网络带宽或 IP 地址资源,防止冲突 |
3.7 调度框架的扩展点执行流程
下图展示了调度框架中扩展点的完整执行流程,以及插件如何在不同阶段介入:
3.8 扩展点开发注意事项
开发警告:
- 性能敏感:Filter 和 Score 扩展点对每个节点都会调用,必须保证执行效率,避免阻塞调度循环。
- 无状态设计:插件应尽量保持无状态,调度状态通过 CycleState 传递,避免全局变量。
- 错误处理:Filter 返回 Unschedulable 时,调度器会记录原因并跳过该节点;返回 Error 会导致调度周期终止。
- 版本兼容:插件接口在不同 Kubernetes 版本间可能发生变化,建议使用 vendor 或 go module 锁定版本。