2. Kubernetes 调度框架基础:Scheduler Framework 架构与扩展点概览
Kubernetes 调度器从传统的“硬编码”调度器演进为可插拔的 Scheduler Framework。该框架将调度流程拆解为多个独立的扩展点,允许开发者通过插件机制注入自定义逻辑。理解这一架构是开发网络拓扑感知调度插件的前提。
2.1 调度框架整体架构
Scheduler Framework 采用“调度周期 + 绑定周期”的双阶段模型。调度周期负责为 Pod 选择一个合适的 Node,绑定周期负责将决策持久化到 API Server。整个流程通过一个核心调度循环(Scheduling Cycle)串联多个扩展点。
核心设计原则: 每个扩展点只负责一个明确的调度子问题,插件可以注册到多个扩展点,但每个扩展点的职责单一。
2.2 核心扩展点详解
Scheduler Framework 定义了 11 个标准扩展点,按执行顺序分为调度周期和绑定周期两大类。下表列出每个扩展点的职责、调用时机和典型应用场景。
| 扩展点 | 所属周期 | 调用时机 | 核心职责 | 典型应用 |
|---|---|---|---|---|
| QueueSort | 调度周期 | 调度队列排序时 | 对调度队列中的 Pod 进行排序 | 优先级调度、QoS 排序 |
| PreFilter | 调度周期 | Filter 之前 | 预处理 Pod 信息,校验前置条件 | 网络拓扑预检查、资源预留校验 |
| Filter | 调度周期 | 遍历所有 Node 时 | 过滤不满足条件的 Node | 节点选择器、端口冲突、网络可达性过滤 |
| PostFilter | 调度周期 | Filter 后无可用 Node 时 | 处理调度失败,尝试替代方案 | 抢占调度、备用节点推荐 |
| PreScore | 调度周期 | Score 之前 | 为打分阶段准备数据 | 网络延迟预计算、拓扑数据预加载 |
| Score | 调度周期 | 对每个过滤后的 Node 打分 | 为 Node 分配分数(0-100) | 网络带宽评分、节点亲和性评分 |
| NormalizeScore | 调度周期 | 所有 Score 完成后 | 归一化多个插件的打分结果 | 权重调整、分数标准化 |
| Reserve | 调度周期 | 选定 Node 后 | 预留资源,防止并发冲突 | 网络带宽预留、IP 地址预留 |
| Permit | 调度周期 | Reserve 之后 | 批准或延迟调度决策 | 网络拓扑一致性校验、等待依赖 Pod |
| PreBind | 绑定周期 | Bind 之前 | 执行绑定前准备工作 | 网络策略注入、CNI 配置下发 |
| Bind | 绑定周期 | 最终绑定 | 将 Pod 绑定到 Node | 默认绑定、自定义绑定逻辑 |
| PostBind | 绑定周期 | Bind 成功后 | 执行绑定后清理或通知 | 网络拓扑状态更新、监控指标上报 |
| Unreserve | 异常处理 | 绑定失败或 Permit 拒绝时 | 释放之前 Reserve 的资源 | 网络资源回滚、IP 地址释放 |
开发提示: 网络拓扑感知插件最常注册的扩展点是 Filter(过滤不可达节点)和 Score(为低延迟节点打高分)。如果涉及资源预留,还需要实现 Reserve 和 Unreserve。
2.3 插件生命周期与注册机制
每个插件必须实现 framework.Plugin 接口(至少包含 Name() 方法),然后按需实现一个或多个扩展点接口。框架通过插件注册表管理所有插件,调度器启动时加载配置文件中指定的插件列表。
// 插件注册示例:网络拓扑感知插件
type TopologyAwarePlugin struct {
handle framework.Handle
}
// 必须实现 Plugin 接口
func (pl *TopologyAwarePlugin) Name() string {
return "TopologyAware"
}
// 注册到 Filter 扩展点
func (pl *TopologyAwarePlugin) Filter(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeInfo *framework.NodeInfo) *framework.Status {
// 检查节点是否满足网络拓扑约束
if !pl.isNodeReachable(nodeInfo.Node(), pod) {
return framework.NewStatus(framework.Unschedulable, "node not reachable from pod's network zone")
}
return framework.NewStatus(framework.Success, "")
}
// 注册到 Score 扩展点
func (pl *TopologyAwarePlugin) Score(ctx context.Context, state *framework.CycleState, pod *v1.Pod, nodeName string) (int64, *framework.Status) {
latency := pl.getNetworkLatency(nodeName, pod)
// 延迟越低,分数越高
score := int64(max(0, 100 - latency/10))
return score, framework.NewStatus(framework.Success, "")
}
2.4 扩展点调用顺序与数据传递
框架通过 framework.CycleState 对象在扩展点之间传递数据。插件可以在 PreFilter 阶段写入计算结果,在 Filter 或 Score 阶段读取使用。这种机制避免了重复计算,是网络拓扑感知插件常用的优化手段。
2.5 扩展点选择策略
开发网络拓扑感知插件时,应根据功能需求选择合适的扩展点。下表总结了不同场景下的推荐扩展点组合。
| 功能需求 | 推荐扩展点 | 说明 |
|---|---|---|
| 过滤不可达节点 | Filter | 直接返回 Unschedulable 状态,阻止调度到不满足网络拓扑约束的节点 |
| 优先选择低延迟节点 | Score | 根据网络延迟或带宽打分,分数越高优先级越高 |
| 预计算拓扑数据 | PreFilter + CycleState | 在 PreFilter 中一次性获取拓扑信息,后续扩展点复用 |
| 预留网络资源 | Reserve + Unreserve | 在 Reserve 中分配带宽或 IP,Unreserve 中释放 |
| 绑定前注入网络配置 | PreBind | 在绑定前将网络策略或 CNI 配置写入 Node 或 Pod 注解 |
| 拓扑一致性校验 | Permit | 在 Permit 中检查所有依赖 Pod 是否已就绪,延迟调度直到条件满足 |
注意事项: 不要在一个扩展点中做过多工作。Filter 应保持轻量,只做快速过滤;复杂的计算逻辑放在 PreFilter 或 PreScore 中,并通过 CycleState 传递结果。避免在 Score 中发起网络请求,这会严重拖慢调度周期。
2.6 框架配置与插件加载
调度器通过 KubeSchedulerConfiguration 配置文件声明启用的插件及其执行顺序。网络拓扑感知插件需要在此配置中注册,并指定在哪些扩展点生效。
# 调度器配置示例(YAML)
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: topology-aware-scheduler
plugins:
filter:
enabled:
- name: "TopologyAware" # 启用网络拓扑过滤
disabled:
- name: "NodeUnschedulable" # 可选:禁用默认插件
score:
enabled:
- name: "TopologyAware" # 启用网络拓扑打分
- name: "NodeResourcesFit" # 保留资源打分
disabled:
- name: "NodeAffinity" # 可选:禁用默认插件
pluginConfig:
- name: "TopologyAware"
args:
latencyThresholdMs: 50 # 自定义参数:延迟阈值
topologyCacheTTLSeconds: 300
通过这种配置方式,网络拓扑感知插件可以无缝集成到现有调度器中,与其他插件协同工作,而无需修改调度器核心代码。