3. Pod调度生命周期与关键对象
当一个 Pod 被创建后,它并不会立刻运行。在它真正落到某个节点上之前,会经历一段由 API Server、调度器和 kubelet 共同参与的“接力”过程。理解这条链路,是排查调度失败、判断 Pod 卡在何处、以及设计资源治理策略的基础。本节围绕“Pending 到 Running”的完整路径,梳理关键对象、调度条件、事件诊断方法,以及常见失败场景的排查任务。
一、调度链路中的关键对象与状态流转
Pod 从创建到运行,核心状态变化可以概括为:Pending → Scheduling → Binding → Running(中间可能穿插 Failed、Succeeded 等终态)。这条链路上有几个必须认识的对象:
- Pod 对象:用户提交的期望状态载体,其中
spec.nodeName为空时表示尚未绑定节点。 - 调度器(kube-scheduler):监听未绑定 Pod,执行过滤(Filter)与打分(Score),选出最优节点。
- Node 对象:提供可分配资源、标签、污点(Taint)、亲和性等调度依据。
- Binding 对象:调度器通过创建 Binding 将 Pod 与节点关联,写入
spec.nodeName。 - kubelet:监听绑定到本节点的 Pod,拉取镜像、创建容器、上报状态。
调度器的工作分为两个阶段:调度周期(Scheduling Cycle)负责选节点,绑定周期(Binding Cycle)负责将结果写回。调度周期内依次执行 PreFilter、Filter、PostFilter、PreScore、Score、Reserve、Permit;绑定周期则执行 PreBind、Bind、PostBind。任一阶段返回失败,Pod 都会停留在 Pending,并产生对应 Event。
二、调度条件:Filter 与 Score 的判定依据
调度器为 Pod 选节点时,先做“硬性过滤”,再做“软性打分”。Filter 阶段会依次检查以下条件,任一不满足即淘汰该节点:
- 资源可用性:节点可分配 CPU/内存是否满足 Pod 的 requests。注意是 requests 而非 limits。
- 污点与容忍:节点 taint 是否被 Pod toleration 覆盖,NoSchedule 与 NoExecute 行为不同。
- 节点选择器与亲和性:nodeSelector、nodeAffinity(requiredDuringScheduling)必须匹配。
- Pod 亲和/反亲和:required 级别的 podAffinity/podAntiAffinity 必须满足拓扑域约束。
- 存储拓扑:PVC 绑定的 PV 若带 nodeAffinity,Pod 只能落到对应节点。
- 端口与卷冲突:hostPort 重复、hostPath 冲突等。
通过 Filter 的节点进入 Score 阶段,按插件权重累加得分,例如 NodeResourcesBalancedAllocation、ImageLocality、InterPodAffinity 等。得分最高者胜出。若所有节点都被过滤,Pod 保持 Pending,并触发 FailedScheduling 事件。
三、事件诊断:从 Event 定位卡点
排查调度问题,第一手信息来自 Event。常用命令:
kubectl describe pod <pod-name> -n <namespace>
# 关注 Events 区域,典型输出:
# Warning FailedScheduling 0/5 nodes are available:
# 3 Insufficient cpu, 2 node(s) had taint {dedicated: gpu}
kubectl get events -n <namespace> --field-selector involvedObject.name=<pod-name>
kubectl get pod <pod-name> -o jsonpath='{.status.conditions}'
解读要点:“0/N nodes are available” 后面的分项就是 Filter 淘汰原因汇总。若出现 pod has unbound immediate PersistentVolumeClaims,说明卡在卷绑定而非节点选择。若 Pod 已绑定节点但容器未起,则问题已转移到 kubelet 侧,应查 kubectl describe node 与 kubelet 日志。
status.phase 与 status.conditions,再看 Event 的 Reason 与 Message,最后结合节点侧 Allocatable、Taint、Label 交叉验证。不要一上来就重启调度器。
四、常见失败场景与排查任务
下面给出四类高频场景,每类都对应一个可执行的排查任务。
| 场景 | 典型 Event | 排查任务 |
|---|---|---|
| 资源不足 | Insufficient cpu/memory | 对比 Pod requests 与节点 Allocatable,检查是否有低效 requests 占用 |
| 污点未容忍 | node(s) had taint | 查看节点 taint,确认 toleration 的 key/effect 是否匹配 |
| 标签/亲和性不匹配 | didn't match node selector | 核对 nodeSelector 与节点 label,检查 affinity 拓扑域 |
| PVC 未绑定 | unbound immediate PVCs | 检查 StorageClass、PV 容量与 accessModes,确认绑定模式 |
以“资源不足”为例,排查任务可具体化为:执行 kubectl describe node <node>,查看 Allocated resources 中 CPU/内存的 Requests 占比;再用 kubectl get pods -A -o json 聚合各节点 requests 总和,找出“申请大、用量小”的 Pod,评估是否调整 requests 或扩容节点。若确认是 requests 虚高,可通过 VPA 或手工下调,再观察 Pod 是否被重新调度。
五、从 Pending 到 Running 的验证闭环
完成调整后,需要验证 Pod 是否真正走完链路。可依次执行:
kubectl get pod -w观察状态从 Pending 变为 ContainerCreating 再到 Running。kubectl get pod -o wide确认NODE列已分配,且 IP 已就绪。kubectl describe pod确认 Events 中不再出现 FailedScheduling,且出现Scheduled与Pulled、Created、Started事件。- 若仍 Pending,回到 Event 重新读取 Reason,形成“观察—定位—调整—再观察”的闭环。
掌握这条链路后,面对 Pending 就不再是盲目猜测。关键是把 Pod 状态、Event 原因、节点条件三者对齐:Pod 卡在调度周期,就看 Filter 淘汰项;卡在绑定周期,就看 PreBind 插件与 PVC;已绑定但未 Running,就转向 kubelet 与容器运行时。调度治理的可靠性,正是建立在这种分层定位能力之上。