3、Pod调度基础:调度器工作原理、调度队列、调度周期、过滤与打分阶段

Pod 调度是 Kubernetes 集群的核心控制面行为之一。调度器(kube-scheduler)负责为新创建的、尚未绑定到节点的 Pod 选择一个最合适的节点。理解调度器的工作原理、调度队列、调度周期以及过滤与打分阶段,是进行集群资源预留和升级窗口管理的基础。

3.1 调度器工作原理概述

kube-scheduler 以独立组件或静态 Pod 形式运行,通过 Kubernetes API Server 监听未调度的 Pod(spec.nodeName 为空)。调度器为每个待调度 Pod 执行一个完整的调度周期,最终将 Pod 绑定到目标节点。其核心工作流程可概括为:

  1. 监听与入队:通过 Informer 机制监听 Pod 变化,将未调度的 Pod 加入调度队列。
  2. 调度周期:从队列中取出 Pod,依次执行过滤(Predicates)和打分(Priorities)阶段。
  3. 绑定周期:将调度结果(Pod 与 Node 的绑定关系)异步写入 API Server。
关键点: 调度器是“先过滤、后打分”的两阶段决策模型。过滤阶段确保节点满足 Pod 的硬性约束,打分阶段在满足条件的节点中选出最优解。

3.2 调度队列

调度队列是调度器的输入缓冲,负责管理待调度的 Pod。Kubernetes 默认使用三种队列结构,确保调度公平性与优先级处理:

队列类型 作用 调度顺序
ActiveQ(活跃队列) 存放所有等待调度的 Pod,按优先级排序 高优先级 Pod 优先出队
BackoffQ(退避队列) 存放调度失败的 Pod,等待重试 退避时间到期后移回 ActiveQ
UnschedulableQ(不可调度队列) 存放因资源不足、节点不可用等原因无法调度的 Pod 集群拓扑变化(如新增节点)时重新评估
实践提示: 在集群升级窗口期间,大量 Pod 可能因节点被标记为不可调度(cordon)而进入 UnschedulableQ。升级完成后,调度器会自动将这批 Pod 移回 ActiveQ 并重新调度。

3.3 调度周期

调度周期是调度器为单个 Pod 执行的核心决策过程,包含两个主要阶段:过滤(Filtering)和打分(Scoring)。整个周期是同步执行的,确保调度决策的原子性。

调度周期流程图 调度队列 过滤阶段 打分阶段 绑定 阶段说明: • 过滤阶段:执行一系列谓词(Predicates),如 PodFitsResources、PodFitsHostPorts、MatchNodeSelector 等。 • 打分阶段:对通过过滤的节点执行优先级函数(Priorities),如 LeastRequestedPriority、BalancedResourceAllocation 等。 • 绑定周期:调度周期结束后,调度器异步将 Pod 绑定到选中的节点。 • 如果过滤阶段没有节点通过,Pod 进入 BackoffQ 或 UnschedulableQ。

3.4 过滤阶段

过滤阶段(又称 Predicates 阶段)的目标是筛选出满足 Pod 运行基本条件的节点。调度器按顺序执行一组内置的过滤插件,任何一个插件返回失败,该节点即被排除。

常用的过滤插件包括:

  • PodFitsResources:检查节点剩余 CPU、内存、GPU 等资源是否满足 Pod 的 requests。
  • PodFitsHostPorts:检查 Pod 请求的端口是否已被占用。
  • MatchNodeSelector:检查 Pod 的 nodeSelector 是否匹配节点标签。
  • PodToleratesNodeTaints:检查 Pod 的 tolerations 是否能容忍节点的 taints。
  • CheckNodeUnschedulable:检查节点是否被标记为不可调度(.spec.unschedulable: true)。
  • NodeAffinity:检查节点亲和性规则。
升级窗口注意事项: 当节点被 kubectl cordon 标记为不可调度后,CheckNodeUnschedulable 插件会直接过滤掉该节点。这是实现“节点优雅下线”的关键机制。

3.5 打分阶段

打分阶段(又称 Priorities 阶段)对通过过滤的节点进行评分,选出最优节点。每个打分插件返回 0-100 的分数,调度器按权重加权求和,最终选择总分最高的节点。

打分插件 评分逻辑 适用场景
LeastRequestedPriority 优先选择资源使用率最低的节点(CPU+内存) 负载均衡,避免热点
BalancedResourceAllocation 优先选择 CPU 和内存使用率最均衡的节点 资源碎片最小化
MostRequestedPriority 优先选择资源使用率最高的节点 集群利用率最大化
NodeAffinityPriority 根据节点亲和性权重打分 拓扑感知调度
TaintTolerationPriority 根据 Pod 容忍的污点数量打分 容忍度高的 Pod 优先调度

3.6 调度器扩展机制

Kubernetes 调度器支持通过 Scheduler Framework 进行扩展,允许用户自定义调度逻辑。框架定义了多个扩展点(Extension Points),分布在调度周期的不同阶段:

  • QueueSort:自定义调度队列排序逻辑。
  • PreFilter / Filter / PostFilter:过滤阶段的前、中、后处理。
  • PreScore / Score / NormalizeScore:打分阶段的前、中、分数归一化。
  • Reserve / Permit / PreBind / Bind / PostBind:绑定周期的扩展点。
工程实践: 在集群升级场景中,可以通过自定义 Filter 插件实现“节点升级优先级”逻辑,例如优先将 Pod 调度到已升级完成的节点,或避免调度到即将下线的节点。

3.7 调度器配置与性能

调度器的性能直接影响集群的 Pod 启动速度。以下参数对调度吞吐量有显著影响:

参数 默认值 说明
--kube-api-qps 50 调度器与 API Server 的 QPS 限制
--kube-api-burst 100 突发请求数
--parallelism 16 并行调度 Pod 的数量
--percentage-of-nodes-to-score 50 打分阶段评估的节点比例(0-100)
性能调优建议: 在大型集群(1000+ 节点)中,适当降低 percentage-of-nodes-to-score 可减少调度延迟,但可能降低调度质量。升级窗口期间建议保持默认值,确保调度公平性。

3.8 调度器与资源预留的关系

资源预留(Resource Reservation)直接影响调度器的过滤阶段。调度器在计算节点可用资源时,会考虑以下因素:

  • 节点容量:status.capacity 中的 CPU、内存等总量。
  • 已分配资源:所有已绑定 Pod 的 requests 总和。
  • 系统预留:kubelet 的 --system-reserved 和 --kube-reserved 参数预留的资源。
  • 节点可分配资源:status.allocatable = 容量 - 系统预留 - kubelet 预留。

调度器使用 status.allocatable 作为节点可用资源的基准,而非 status.capacity。因此,合理的资源预留配置可以防止调度器将 Pod 分配到资源已被系统进程占用的节点。

升级窗口最佳实践: 在升级前,通过 kubectl describe node 检查节点的 Allocatable 值,确保预留资源充足。如果发现 Allocatable 远低于 Capacity,说明系统预留过高,可能导致 Pod 调度失败。