3. Pod生命周期:Pod状态详解与重启策略

聊到Pod,就绕不开它的生命周期。说白了,Pod就像咱们运维的一个“微服务进程”,从生到死,状态一目了然。我个人习惯,排查问题第一件事就是 kubectl get pod 看状态,这比看日志还快。

3.1 Pod的五大状态

K8s里Pod的状态其实就五种:Pending、Running、Succeeded、Failed、Unknown。嗯,这里要注意,不是所有状态都会出现,但每个状态背后都有故事。

状态 含义 常见原因
Pending Pod已被K8s接受,但容器还没启动 镜像拉取中、资源不足、PVC未就绪
Running 至少一个容器正在运行 正常状态,但可能内部有异常
Succeeded 所有容器正常退出(退出码0) Job任务完成,CronJob执行成功
Failed 至少一个容器以非0退出码退出 应用崩溃、OOM、配置错误
Unknown Kubelet无法与API Server通信 节点宕机、网络分区、kubelet挂掉

核心观点:Pod状态只是“表象”,真正决定Pod生死的是容器的退出码和重启策略。你想想看,一个Running的Pod,内部容器可能已经重启了10次,但状态还是Running。

3.2 状态详解:从Pending到Unknown

3.2.1 Pending——等待中的焦虑

Pending是最常见的“卡住”状态。我记得有一次,vLLM服务一直Pending,我查了半天,发现是PVC的StorageClass没配对,卷挂不上。说白了,Pending就是调度或初始化没完成。

排查Pending,我一般三步走:

  1. kubectl describe pod <pod-name> 看Events
  2. 检查节点资源:kubectl describe node
  3. 看镜像拉取策略:是不是私有仓库没配Secret

我的经验:vLLM模型镜像通常很大(几十GB),Pending时间可能长达几分钟。别慌,先看Events里有没有“ImagePullBackOff”或“ErrImagePull”。

3.2.2 Running——看似平静的湖面

Running不代表万事大吉。我曾经遇到过,vLLM Pod状态Running,但推理请求全部超时。为什么?因为容器启动了,但模型加载失败,进程卡住了。

Running状态下,我建议关注:

  • 容器重启次数(RESTARTS列)
  • 资源使用率(kubectl top pod
  • Readiness探针是否通过

3.2.3 Succeeded——完美的谢幕

Succeeded状态通常出现在Job或CronJob中。对于vLLM这种长服务,很少见到Succeeded。如果你看到Succeeded,说明Pod里的主容器正常退出了——嗯,这通常意味着你的推理服务意外终止了。

3.2.4 Failed——翻车现场

Failed是最让人头疼的状态。容器退出码非0,原因五花八门。我整理了一份常见退出码对照表:

退出码 含义 vLLM场景举例
0 正常退出 手动停止Pod
1 一般错误 模型路径错误、CUDA初始化失败
137 SIGKILL(OOM) 显存不足被杀死
139 SIGSEGV(段错误) GPU驱动问题或模型bug
143 SIGTERM(优雅终止) Pod被驱逐或滚动更新

避坑指南:我曾经遇到vLLM Pod反复Failed,退出码137。查了半天,发现是limits里显存设小了,模型加载时直接OOM。记住,vLLM的显存需求 = 模型参数大小 × 2(FP16) + 推理缓存。

3.2.5 Unknown——失联的Pod

Unknown状态比较少见,但一旦出现,基本是节点层面的问题。Kubelet挂了,或者网络不通,API Server收不到心跳。这时候,你连 kubectl logs 都跑不了。

我的处理方式:

  • 先检查节点状态:kubectl get node
  • SSH到节点看kubelet日志
  • 如果节点真挂了,强制删除Pod:kubectl delete pod --force

3.3 重启策略:Pod的“复活”机制

重启策略决定了Pod里的容器挂了之后怎么办。K8s支持三种策略:

策略 行为 适用场景
Always 默认值 容器退出后总是重启 长服务(vLLM、Web服务)
OnFailure 非0退出码才重启 只有失败才重启 批处理任务、数据清洗
Never 从不重启 容器退出后Pod进入Succeeded/Failed 一次性Job、测试

对于vLLM推理服务,我强烈建议用 Always。为什么?因为推理服务挂了必须立刻恢复,哪怕是因为OOM被杀,重启后也能继续服务。

重要提醒:重启策略只影响Pod内的容器,不影响Pod本身。Pod的“重启”其实是Kubelet重新创建容器,Pod的UID和IP不变。但如果你用 kubectl delete pod,那是整个Pod重建,IP会变。

3.4 状态流转与重启策略的联动

Pod状态和重启策略是联动的。举个例子:

  • 容器退出码0 + 策略Always → 容器重启,Pod保持Running
  • 容器退出码1 + 策略OnFailure → 容器重启,Pod保持Running
  • 容器退出码1 + 策略Never → Pod进入Failed
  • 容器退出码0 + 策略OnFailure → Pod进入Succeeded

你想想看,如果vLLM因为OOM退出(退出码137),策略是Always,Kubelet会立刻拉起新容器。但如果OOM反复发生,容器会不断重启,Pod状态还是Running,但RESTARTS列会一直涨。这时候,你需要看日志或者用 kubectl describe pod 看Last State。

我的习惯:在Deployment的yaml里,我会把restartPolicy设为Always,同时配合livenessProbe。如果容器活着但服务挂了(比如模型加载卡住),livenessProbe会杀死容器,然后重启策略再把它拉起来。双重保险。

3.5 实战:vLLM Pod状态排查流程

最后,分享一个我常用的排查流程。当vLLM Pod状态异常时,我按这个顺序查:

  1. kubectl get pod -o wide 看状态和节点
  2. 如果Pending → kubectl describe pod 看Events
  3. 如果Running但服务不可用 → kubectl logs <pod-name> 看启动日志
  4. 如果CrashLoopBackOff → kubectl logs --previous <pod-name> 看上一次的日志
  5. 如果Unknown → 检查节点健康

嗯,这套流程我用了好几年,基本覆盖了90%的问题。剩下的10%,就得靠经验和运气了。

Pod生命周期状态流转图 Pending Running Succeeded Failed Unknown 调度成功 退出码0 + Never/OnFailure 退出码非0 + Never 节点失联 重启(Always/OnFailure) 图例: Pending Running Succeeded Failed Unknown 重启

这张图展示了Pod状态的完整流转。注意看,Running状态有一个自循环箭头,代表重启策略触发的容器重启。这也是为什么你经常看到Pod一直Running,但RESTARTS列在涨。