4. 调度器扩展机制:调度器扩展点(Scheduling Framework)与插件化架构
Kubernetes 调度器从 v1.19 开始全面转向 Scheduling Framework,将调度流程拆解为多个明确定义的扩展点(Extension Points),并通过插件(Plugin)机制实现可插拔的调度逻辑。这种架构使得用户无需修改调度器核心代码,即可注入自定义调度策略、资源评分规则甚至抢占逻辑。
4.1 调度器扩展点总览
Scheduling Framework 将一次 Pod 调度决策划分为两个阶段:Scheduling Cycle(调度周期)和 Binding Cycle(绑定周期)。每个周期内包含若干扩展点,插件可以注册到这些扩展点上执行特定逻辑。
| 阶段 | 扩展点 | 执行时机 | 典型插件用途 |
|---|---|---|---|
| Scheduling Cycle | QueueSort | 对调度队列中的 Pod 排序 | 自定义 Pod 优先级排序策略 |
| PreFilter | 过滤前预处理或校验 Pod 信息 | 检查 Pod 是否满足资源预留条件 | |
| Filter | 过滤不满足条件的节点 | 节点污点容忍、端口冲突检查 | |
| PostFilter | 过滤后无可用节点时的处理 | 抢占(Preemption)逻辑 | |
| PreScore / Score / NormalizeScore | 对通过过滤的节点进行评分 | 资源均衡、亲和性打分 | |
| Binding Cycle | Reserve | 在绑定前预留节点资源 | 确保资源不被其他 Pod 抢占 |
| Permit | 批准或延迟绑定 | 外部准入控制、多调度器协调 | |
| PreBind / Bind / PostBind | 执行绑定及绑定后处理 | 自定义绑定逻辑、绑定后清理 |
关键理解: Filter 扩展点决定节点“能不能用”,Score 扩展点决定节点“好不好用”。OPA Gatekeeper 策略通常作用于 Filter 扩展点,而调度器参数(如资源权重)作用于 Score 扩展点。
4.2 插件化架构与注册机制
调度器插件以 Go 接口方式实现,通过 scheduler-config.yaml 配置文件注册到对应扩展点。每个插件可以同时实现多个扩展点接口。
# scheduler-config.yaml 示例
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: custom-scheduler
plugins:
filter:
enabled:
- name: "NodeResourcesFit"
- name: "MyCustomFilter" # 自定义过滤插件
disabled:
- name: "NodeUnschedulable"
score:
enabled:
- name: "NodeResourcesBalancedAllocation"
weight: 2
- name: "MyCustomScorer"
weight: 5
pluginConfig:
- name: "MyCustomFilter"
args:
forbiddenLabels: ["spot-instance"]
实践提示: 调度器配置支持多 Profile,每个 Profile 可以绑定不同的插件组合和权重。结合 OPA Gatekeeper 的命名空间标签,可以实现“不同租户使用不同调度器 Profile”的隔离策略。
4.3 调度框架核心流程 SVG 图
下图展示了 Scheduling Framework 中主要扩展点的执行顺序,以及插件如何挂载到这些扩展点上:
4.4 插件生命周期与状态管理
调度器插件在运行时遵循明确的生命周期管理,确保状态一致性和并发安全:
- 注册阶段: 调度器启动时读取配置,实例化所有启用的插件,并注册到对应扩展点。
- 调度阶段: 每个 Pod 调度周期内,插件按扩展点顺序依次执行。Filter 插件返回
Success、Unschedulable或Error;Score 插件返回 0-100 的整数分数。 - 状态清理: 绑定完成后,调度器调用
PostBind插件清理临时状态。如果绑定失败,Unreserve插件负责释放预留资源。
避坑指南: 自定义插件必须实现
Name() 方法返回唯一名称,且不能与内置插件重名。插件状态(如缓存)需要自行管理并发锁,调度器不提供状态隔离。
4.5 调度器参数与插件协同配置
调度器参数(如 percentageOfNodesToScore、bindTimeoutSeconds)与插件配置共同决定调度行为。下表列出关键协同参数:
| 参数名称 | 默认值 | 影响范围 | 与插件协同说明 |
|---|---|---|---|
percentageOfNodesToScore |
50% | Filter / Score | 控制参与评分的节点比例,影响 Filter 插件的执行范围 |
bindTimeoutSeconds |
100 | Bind | 自定义 Bind 插件超时时间,避免长时间阻塞 |
podInitialBackoffSeconds |
1 | QueueSort | Pod 调度失败后的重试退避,影响 QueueSort 排序 |
profiles[].plugins.score[].weight |
1 | Score | 每个 Score 插件的权重,决定最终评分占比 |
4.6 插件化架构与 OPA Gatekeeper 集成点
OPA Gatekeeper 策略可以通过以下两种方式与调度器插件协同:
- Filter 扩展点集成: 在自定义 Filter 插件中调用 OPA 的 REST API,将 Pod 和节点信息作为输入,根据 Gatekeeper 策略返回
Success或Unschedulable。 - PreScore 扩展点集成: 在评分前通过 OPA 策略调整节点候选集,例如剔除不符合安全策略的节点。
架构优势: 调度器插件化架构使得 OPA 策略可以“无侵入”地嵌入调度流程,无需修改调度器核心代码。策略变更只需更新插件配置或 OPA 规则,调度器热加载即可生效。
4.7 插件化架构分层 SVG 图
下图展示了调度器插件化架构的分层关系,从核心调度器到扩展点、插件层,再到外部策略引擎(如 OPA):
实战要点: 在 Filter 扩展点集成 OPA 时,建议将 OPA 查询结果缓存到插件本地,避免每个 Pod 调度都发起 HTTP 调用。缓存 TTL 可根据策略变更频率设置,通常 5-10 秒即可。