3. Pod 调度基础:Pod 调度生命周期、调度队列、调度周期与绑定周期
Pod 调度是 Kubernetes 调度器的核心职责。理解 Pod 从创建到被调度到合适节点的完整生命周期,是掌握调度优化与故障排查的前提。本章将深入剖析调度器内部的三个关键阶段:调度队列、调度周期与绑定周期,并梳理 Pod 调度的整体生命周期。
3.1 Pod 调度生命周期全景
一个 Pod 从提交到运行,其调度相关生命周期可划分为以下阶段:
| 阶段 | 描述 | 关键组件 |
|---|---|---|
| 1. 创建与入队 | 用户通过 API Server 创建 Pod,调度器通过 Informer 机制监听未调度的 Pod,将其加入调度队列。 | API Server、Informer、Scheduling Queue |
| 2. 出队与调度周期 | 调度器从队列中取出一个 Pod,执行预选(Predicates)和优选(Priorities)算法,选出最优节点。 | Scheduler Framework、Filter、Score |
| 3. 绑定周期 | 调度器将选定的节点信息写入 Pod 的 NodeName 字段,并异步执行绑定操作。 |
Binder、API Server |
| 4. 节点确认与运行 | Kubelet 监听到 Pod 被调度到本节点,拉取镜像并启动容器。 | Kubelet、Container Runtime |
关键认知: 调度器只负责“决策”,不负责“执行”。调度周期决定 Pod 应该去哪个节点,绑定周期负责将这个决策持久化到 etcd,而真正的容器启动由 Kubelet 完成。
3.2 调度队列:Pod 的等待区
调度队列是调度器的入口,负责管理所有等待调度的 Pod。Kubernetes 默认使用 PriorityQueue,它内部维护了三个子队列:
- activeQ:存放所有准备好被调度的 Pod,按优先级排序。
- backoffQ:存放调度失败的 Pod,经过退避时间后重新进入 activeQ。
- unschedulableQ:存放因资源不足、节点污点等原因无法调度的 Pod,等待集群状态变化后重新尝试。
调度队列核心机制:
- 优先级排序:Pod 优先级(PriorityClass)越高,出队越早。
- 抢占式调度:高优先级 Pod 可以抢占低优先级 Pod 的资源。
- 退避机制:调度失败的 Pod 会进入 backoffQ,退避时间指数增长(如 1s、2s、4s...),避免频繁重试。
- 事件驱动:当集群资源变化(如新节点加入、Pod 删除)时,unschedulableQ 中的 Pod 会被重新评估。
3.3 调度周期:预选与优选
调度周期是调度器的核心决策阶段,分为两个步骤:预选(Filter) 和 优选(Score)。
3.3.1 预选阶段(Filtering)
预选阶段的目标是快速过滤掉不满足条件的节点,生成一个可行节点列表。常见的预选策略包括:
| 预选策略 | 作用 | 典型场景 |
|---|---|---|
| NodeResourcesFit | 检查节点剩余资源(CPU、内存)是否满足 Pod 请求 | Pod 请求 4C8G,节点剩余不足则过滤 |
| NodeName | 检查 Pod 是否指定了 nodeName |
直接指定节点 |
| PodTopologySpread | 确保 Pod 在拓扑域(如区域、节点)中均匀分布 | 高可用部署 |
| TaintToleration | 检查 Pod 是否能容忍节点的污点 | 专用节点、GPU 节点 |
| NodeAffinity | 检查节点标签是否满足 Pod 的节点亲和性规则 | 将 Pod 调度到特定区域 |
3.3.2 优选阶段(Scoring)
优选阶段对预选通过的节点进行打分,选出最优节点。每个优选策略会返回一个 0-100 的分数,最终加权求和:
最终分数 = Σ(策略分数 × 策略权重) / 总权重
常见的优选策略:
- NodeResourcesBalancedAllocation:优先选择资源利用率均衡的节点(CPU 和内存使用率接近)。
- NodeResourcesLeastAllocated:优先选择资源剩余最多的节点(负载分散)。
- NodeResourcesMostAllocated:优先选择资源利用率最高的节点(资源集中)。
- ImageLocality:优先选择已缓存 Pod 所需镜像的节点,减少镜像拉取时间。
- InterPodAffinity:根据 Pod 间的亲和性/反亲和性打分。
注意: 默认调度器使用 LeastAllocated 策略,适合负载分散场景。如果集群资源紧张,可考虑切换为 MostAllocated 以提高资源利用率。ImageLocality 策略在镜像拉取成为瓶颈时尤为重要,后续章节会深入讲解。
3.4 绑定周期:将决策写入集群
调度周期结束后,调度器已经选定了目标节点。绑定周期的任务是将这个决策持久化:
- 假设(Assume):调度器先在缓存中假设 Pod 已被调度到该节点,更新缓存状态。
- 绑定(Bind):调度器通过 API Server 更新 Pod 的
spec.nodeName字段。 - 确认(Reserve):Kubelet 监听到 Pod 被调度到本节点,开始拉取镜像并启动容器。
绑定周期关键点:
- 异步绑定:调度器不会等待绑定完成再处理下一个 Pod,而是异步执行绑定操作,提高吞吐量。
- 乐观锁定:绑定操作使用乐观锁(ResourceVersion),避免并发冲突。
- 绑定失败处理:如果绑定失败(如节点已满),调度器会将 Pod 重新放回队列,并标记为调度失败。
3.5 调度失败与重试机制
Pod 调度可能因多种原因失败,调度器内置了完善的重试机制:
| 失败原因 | 处理方式 | 重试间隔 |
|---|---|---|
| 资源不足 | 进入 unschedulableQ,等待集群资源变化 | 事件触发 |
| 节点污点不匹配 | 进入 unschedulableQ,等待节点污点变化 | 事件触发 |
| 抢占失败 | 进入 backoffQ,指数退避 | 1s, 2s, 4s, 8s... |
| 绑定失败 | 重新进入调度周期 | 立即重试(有限次数) |
排查建议: 使用
kubectl describe pod <pod-name> 查看 Events 字段,可以快速定位调度失败原因。常见错误包括 0/4 nodes are available(资源不足)和 node(s) had taints(污点不匹配)。
3.6 本章小结
- Pod 调度生命周期包括:入队 → 调度周期(预选+优选) → 绑定周期(假设+绑定) → Kubelet 确认。
- 调度队列使用 PriorityQueue,包含 activeQ、backoffQ、unschedulableQ 三个子队列。
- 调度周期通过预选过滤不可行节点,通过优选打分选出最优节点。
- 绑定周期将调度决策持久化到 etcd,并通知 Kubelet 启动容器。
- 调度失败时,Pod 会根据失败原因进入不同的队列等待重试。