1. K8s 调度器概述
1.1 调度器在 K8s 架构中的位置
Kubernetes 调度器(kube-scheduler)是控制平面的核心组件之一,位于 API Server 与工作节点之间。它负责监听 API Server 中未被调度的 Pod(spec.nodeName 为空),通过一系列调度算法为每个待调度 Pod 选择最合适的节点,并将绑定结果写回 API Server。
架构定位要点:
- 调度器是控制平面中唯一负责“节点选择”的组件
- 调度器不直接与 kubelet 通信,所有交互通过 API Server 完成
- 调度器是可插拔的,支持自定义调度器与多调度器共存
1.2 调度器核心职责
kube-scheduler 的核心职责可以概括为三个层次:监听、过滤、打分。调度器不负责 Pod 的创建、运行或销毁,只负责为“待调度”的 Pod 找到最合适的节点。
| 职责层次 | 说明 | 关键动作 |
|---|---|---|
| 监听与排队 | 通过 Informer 机制监听 API Server 中 spec.nodeName 为空的 Pod |
将待调度 Pod 放入调度队列(Scheduling Queue) |
| 过滤(Predicates) | 从所有节点中筛选出满足 Pod 资源需求、亲和性、污点容忍等硬性条件的节点 | 执行一系列谓词检查,输出候选节点列表 |
| 打分(Priorities) | 对候选节点进行优先级评分,选择最优节点 | 执行一系列优先级函数,加权求和后选出最高分节点 |
| 绑定(Binding) | 将 Pod 与选中节点的绑定关系写入 API Server | 创建 Binding 对象,更新 Pod 的 spec.nodeName |
调度器职责边界: 调度器不保证 Pod 一定能成功运行在目标节点上。kubelet 在节点上启动 Pod 时仍可能因资源竞争、镜像拉取失败等原因导致 Pod 运行失败。调度器只负责“选择”,不负责“执行”。
1.3 调度工作流程简介
一个 Pod 从创建到完成调度的完整流程包含以下关键步骤。理解这个流程是后续排查调度失败问题的基础。
- Pod 创建: 用户通过 kubectl 或 API 创建 Pod,API Server 将 Pod 写入 etcd,此时
spec.nodeName为空。 - 调度器监听: kube-scheduler 的 Informer 监听到新的未调度 Pod,将其加入调度队列。
- 过滤阶段: 调度器对集群中所有节点执行过滤算法,剔除不满足条件的节点。常见过滤条件包括:资源不足、端口冲突、节点选择器不匹配、污点不兼容等。
- 打分阶段: 对过滤后的候选节点执行打分算法,计算每个节点的优先级分数。常见打分策略包括:资源余量、Pod 分布均衡、亲和性权重等。
- 选择节点: 选择得分最高的节点作为目标节点。如果多个节点得分相同,调度器会随机选择一个。
- 绑定: 调度器通过 API Server 创建 Binding 对象,将 Pod 绑定到目标节点。kubelet 监听到绑定事件后,在节点上启动 Pod。
常见误解: 调度器不是实时响应的。默认情况下,调度器使用 调度队列 + 调度周期 的模式工作。一个调度周期包含过滤、打分、绑定三个阶段。如果集群规模较大或 Pod 数量较多,调度延迟会显著增加。这也是后续章节中“性能调优”要解决的核心问题。
1.4 调度器关键组件与数据结构
了解调度器内部的关键组件有助于深入理解调度流程。下表列出了调度器运行时的核心模块:
| 组件/数据结构 | 作用 | 说明 |
|---|---|---|
| Scheduling Queue | 存储待调度的 Pod | 支持优先级队列、Pod 重入队、Backoff 机制 |
| Node Cache | 缓存集群节点信息 | 避免每次调度都从 API Server 拉取全量节点数据 |
| Predicates | 过滤算法集合 | 默认包含 10+ 个内置谓词,如 CheckNodeUnschedulable、PodFitsResources 等 |
| Priorities | 打分算法集合 | 默认包含 10+ 个内置优先级函数,如 LeastRequestedPriority、BalancedResourceAllocation 等 |
| Extenders | 调度扩展点 | 允许用户通过 HTTP 方式扩展调度逻辑,适用于自定义过滤/打分 |
| Scheduler Framework | 插件化调度框架 | K8s v1.19+ 引入,支持通过插件扩展调度流程的各个阶段 |
调度器性能关键指标:
- 调度吞吐量: 单位时间内成功调度的 Pod 数量(Pods/sec)
- 调度延迟: 从 Pod 进入调度队列到完成绑定的时间(ms)
- 调度队列深度: 等待调度的 Pod 数量,反映调度压力
- 调度失败率: 因无可用节点等原因导致调度失败的 Pod 比例