3. Pod 调度基础:Pod 生命周期、调度队列、调度周期、绑定过程详解
Pod 是 Kubernetes 中最小的调度与部署单元。理解 Pod 从创建到运行在目标节点上的完整过程,是掌握调度优化的前提。本章深入剖析 Pod 的生命周期阶段、调度队列的排队机制、调度周期的核心流程以及绑定过程的底层实现。
3.1 Pod 生命周期阶段
Pod 从提交到终止会经历多个状态阶段。kubelet 和 kube-scheduler 共同维护这些状态转换。
| 阶段 | 状态值 | 说明 |
|---|---|---|
| Pending | Pod 已被 API Server 接受,但尚未调度到节点 | 等待调度器分配节点,或正在拉取镜像 |
| Running | Pod 已绑定到节点,所有容器已启动 | 至少有一个容器处于运行或启动状态 |
| Succeeded | Pod 中所有容器正常退出 | 通常用于 Job/CronJob 场景 |
| Failed | Pod 中至少一个容器以非零状态退出 | 调度器不会重试,需人工介入 |
| Unknown | API Server 无法获取 Pod 状态 | 通常由节点失联或网络分区引起 |
关键指标: Pod 在 Pending 阶段的停留时间(Pod Startup Latency)是衡量调度性能的核心指标。生产环境中,P99 延迟应控制在 5s 以内。
3.2 调度队列:Pod 等待调度的排队机制
kube-scheduler 内部维护三个优先级队列,用于管理等待调度的 Pod。队列的设计直接影响调度吞吐量和公平性。
- activeQ:存放所有等待调度的 Pod,按优先级(PriorityClass)和创建时间排序。调度器主循环每次从 activeQ 头部取出一个 Pod。
- backoffQ:存放调度失败的 Pod,经过退避时间后重新进入 activeQ。退避时间指数增长(1s → 2s → 4s → …),最大 120s。
- unschedulableQ:存放因资源不足、节点污点、亲和性不满足等原因无法调度的 Pod。当集群资源变化(如新节点加入)时,会批量移回 activeQ。
优化建议: 如果集群中存在大量低优先级 Pod 阻塞高优先级 Pod,可以调整
scheduler.alpha.kubernetes.io/critical-pod 注解或使用 PriorityClass 抢占机制。
3.3 调度周期:从 Pod 出队到节点选择
调度周期是调度器为单个 Pod 选择最佳节点的完整过程,分为两个阶段:过滤(Filtering) 和 打分(Scoring)。
3.3.1 过滤阶段
过滤阶段遍历所有节点,剔除不满足 Pod 约束的节点。常见的过滤插件包括:
- NodeResourcesFit:检查节点剩余 CPU/内存是否满足 Pod 请求。
- NodeName:检查 Pod 是否指定了
nodeName。 - PodTopologySpread:检查拓扑分布约束。
- TaintToleration:检查节点污点与 Pod 容忍度。
- NodeAffinity:检查节点亲和性规则。
3.3.2 打分阶段
对通过过滤的节点进行评分(0-100),选择总分最高的节点。如果多个节点分数相同,调度器会随机选择一个。常见打分插件:
- NodeResourcesBalancedAllocation:优先选择资源利用率均衡的节点。
- ImageLocality:优先选择已缓存 Pod 所需镜像的节点。
- InterPodAffinity:优先满足 Pod 间亲和性/反亲和性。
注意: 如果过滤后可用节点数为 0,调度器会将 Pod 放入 unschedulableQ,并记录调度失败事件。此时应检查集群资源是否充足、污点/容忍度是否匹配。
3.4 绑定过程:将 Pod 与节点关联
调度器选定节点后,通过绑定过程将 Pod 与节点建立关联。绑定过程涉及多个组件协作:
- 调度器发起绑定请求:调度器调用 API Server 的
POST /api/v1/namespaces/{ns}/pods/{name}/binding接口,将 Pod 的spec.nodeName设置为目标节点。 - API Server 持久化绑定:API Server 将绑定信息写入 etcd,并更新 Pod 状态为
Bound。 - kubelet 感知绑定:kubelet 通过 watch 机制检测到 Pod 被绑定到本节点,开始创建容器。
- kubelet 启动容器:kubelet 调用容器运行时(如 containerd)拉取镜像、创建并启动容器。
3.5 调度周期与绑定过程的完整流程
将上述所有环节串联起来,Pod 从创建到运行的完整调度流程如下:
| 步骤 | 组件 | 操作 | 耗时参考 |
|---|---|---|---|
| 1 | API Server | 接收 Pod 创建请求,写入 etcd | ~50ms |
| 2 | 调度器 | 从 activeQ 取出 Pod,开始调度周期 | ~10ms |
| 3 | 调度器 | 过滤阶段:遍历所有节点,剔除不满足条件的节点 | ~100ms(1000 节点集群) |
| 4 | 调度器 | 打分阶段:对剩余节点评分,选择最优节点 | ~80ms |
| 5 | 调度器 | 发起绑定请求到 API Server | ~20ms |
| 6 | API Server | 持久化绑定信息到 etcd | ~30ms |
| 7 | kubelet | watch 到绑定事件,开始创建容器 | ~10ms |
| 8 | kubelet | 拉取镜像、启动容器(镜像已缓存时) | ~500ms |
性能优化切入点: 步骤 3-4(过滤+打分)是调度器 CPU 密集型操作,可通过
--kube-api-qps 和 --kube-api-burst 参数调整调度器与 API Server 的通信速率。步骤 8 的镜像拉取时间可通过 ImageLocality 打分插件和 P2P 镜像分发工具(如 Dragonfly)优化。
3.6 常见调度失败场景与排查方法
- 0/1 nodes are available: 1 Insufficient cpu:节点 CPU 资源不足。检查 Pod 的
requests.cpu是否过大,或集群需要扩容。 - 0/1 nodes are available: 1 node(s) had taint:节点存在污点,Pod 没有对应的容忍度。添加
tolerations或移除节点污点。 - 0/1 nodes are available: 1 node(s) didn't match pod affinity/anti-affinity:Pod 间亲和性规则无法满足。检查
podAffinity和podAntiAffinity配置。 - Pod 长时间处于 Pending 状态:使用
kubectl describe pod <pod-name>查看 Events 字段,定位具体失败原因。
诊断命令:
kubectl get events --sort-by='.lastTimestamp' | grep <pod-name> 可以快速查看 Pod 相关的调度事件。