Kubernetes拓扑分布约束与抢占事件诊断 - 第1节

1. 课程导论:K8s 调度器整体架构与调度框架概述

Kubernetes 调度器(kube-scheduler)是控制平面中负责将 Pod 绑定到合适 Node 的核心组件。其决策质量直接影响集群的资源利用率、应用性能与运维稳定性。本章首先建立调度器的整体架构认知,再聚焦于拓扑分布约束与抢占事件这两个关键调度策略。

1.1 调度器整体架构

kube-scheduler 采用“调度队列 + 调度框架 + 绑定回写”的三层架构。调度框架(Scheduling Framework)自 v1.19 起成为扩展点标准,允许用户通过插件机制定制调度行为。

架构要点:调度器不直接与 Node 通信,而是通过 API Server 监听 Pod 与 Node 的变更事件,将调度决策写入 Pod 的 spec.nodeName 字段。
K8s 调度器整体架构图 K8s 调度器整体架构 API Server 调度队列 (PriorityQueue / 延迟队列) 调度框架 (扩展点 + 插件链) 绑定回写 (Bind / Reserve) 调度周期(Scheduling Cycle) ① 从队列取 Pod ② 执行 PreFilter → Filter → PostFilter ③ 执行 PreScore → Score → NormalizeScore ④ 执行 Reserve → Permit → PreBind → Bind → PostBind

1.2 调度框架核心扩展点

调度框架将调度周期划分为多个扩展点(Extension Points),每个扩展点可插入一个或多个插件。下表列出与拓扑分布约束和抢占事件最相关的扩展点:

扩展点 执行阶段 与拓扑/抢占的关系
PreFilter 过滤前预处理 校验 Pod 的拓扑分布约束声明,预计算所需拓扑域
Filter 节点过滤 检查每个 Node 是否满足 Pod 的拓扑分布约束(topologySpreadConstraints)
PostFilter 过滤后处理 当无可用 Node 时,触发抢占逻辑(Preemption)
Score 节点打分 对满足约束的 Node 按拓扑分布均匀度打分,优先选择分布更均衡的 Node
Reserve 资源预留 抢占成功后,预留被抢占 Pod 的资源,防止其他调度器占用
实践提示:拓扑分布约束在 Filter 阶段做硬性检查,在 Score 阶段做软性优化。如果集群中大量 Pod 因拓扑约束无法调度,应优先检查 Filter 阶段的日志,而非 Score 阶段的打分结果。

1.3 拓扑分布约束在调度中的角色

拓扑分布约束(Topology Spread Constraints)是 v1.19 进入 Beta、v1.24 进入 GA 的调度特性。它允许用户定义 Pod 在集群拓扑域(如 zone、region、hostname)上的分布规则,避免 Pod 集中部署在少数节点或可用区。

1.3.1 核心参数

  • topologyKey:拓扑域键,如 topology.kubernetes.io/zone、kubernetes.io/hostname。
  • maxSkew:最大偏斜度,表示任意两个拓扑域之间 Pod 数量的最大差值。
  • whenUnsatisfiable:不满足约束时的行为,可选 DoNotSchedule(硬约束)或 ScheduleAnyway(软约束)。
  • labelSelector:用于匹配 Pod 的标签选择器,决定哪些 Pod 参与分布计数。
调度角色:拓扑分布约束在 Filter 阶段作为硬性准入条件,在 Score 阶段作为软性优化目标。硬约束保证 Pod 不会过度集中,软约束在满足硬约束的前提下尽量均匀分布。
拓扑分布约束调度流程 拓扑分布约束调度流程 Pod 携带拓扑约束 PreFilter:解析约束 提取 topologyKey / maxSkew Filter:硬约束检查 maxSkew 是否超限? Score:软性优化 均匀度打分 调度结果 ✅ Filter 通过 + Score 最高 → 选定最优 Node ❌ Filter 不通过 → 触发 PostFilter(抢占或不可调度) ⚠️ 软约束(ScheduleAnyway)即使超限也继续调度

1.4 抢占事件在调度中的角色

抢占(Preemption)是调度器在 PostFilter 扩展点触发的应急机制。当高优先级 Pod 无法找到满足所有约束的 Node 时,调度器会尝试驱逐低优先级 Pod 来释放资源。

1.4.1 抢占触发条件

  • Pod 经过 Filter 阶段后,所有 Node 均不满足调度条件。
  • Pod 的 priorityClassName 对应的优先级高于被抢占 Pod。
  • 被抢占 Pod 的 preemptionPolicy 为 PreemptLowerPriority(默认值)。

1.4.2 抢占流程

步骤 操作 说明
1 候选节点筛选 找出所有 Node,计算驱逐低优先级 Pod 后能否满足高优先级 Pod 的资源需求
2 受害者选择 在每个候选 Node 上选择优先级最低、且与高优先级 Pod 不冲突的 Pod 作为受害者
3 抢占裁决 选择受害者数量最少、总优先级最低的 Node 作为最终抢占目标
4 资源预留 在 Reserve 扩展点预留资源,防止其他调度器占用
5 驱逐与绑定 通过 API Server 删除受害者 Pod,将高优先级 Pod 绑定到目标 Node
运维警告:抢占事件会触发 Pod 驱逐,导致服务中断。生产环境中应严格控制优先级配置,避免频繁抢占。建议结合 priorityClass 的 globalDefault 和 preemptionPolicy: Never 来限制非关键 Pod 的抢占行为。

1.4.3 拓扑分布约束与抢占的交互

当拓扑分布约束与抢占同时生效时,调度器需要额外考虑:

  • 抢占后,目标 Node 的拓扑域内 Pod 数量变化可能违反其他 Pod 的 maxSkew 约束。
  • 调度器在 PostFilter 阶段会重新计算拓扑分布,确保抢占后的分布仍满足硬约束。
  • 如果抢占导致拓扑分布超限,调度器会放弃该 Node,继续评估其他候选节点。
调优关键:拓扑分布约束与抢占的交互是调度调优的高频难点。建议在测试环境中使用 kube-scheduler 的 --v=5 日志级别,观察 PostFilter 阶段的决策日志,确认抢占是否因拓扑约束被拒绝。