深色模式
Pod 生命周期与重启策略
摘要:本文讲清 Pod 从创建到删除经历的阶段、容器状态的含义,restartPolicy 三种取值的行为差异,优雅退出时间怎么设,以及 Init 容器能解决什么问题。
适用环境
- 可用 K8s 集群 +
kubectl - 示例镜像:
nginx:alpine、busybox
操作步骤
一、Pod 阶段(Phase)释义
bash
kubectl get pod -o custom-columns=NAME:.metadata.name,PHASE:.status.phase1
| Phase | 含义 | 常见原因 |
|---|---|---|
| Pending | 已创建但未调度或未起容器 | 资源不足、镜像拉取中、调度失败 |
| Running | 至少一个容器在运行 | 正常 |
| Succeeded | 所有容器成功退出且不再重启 | Job/CronJob 完成 |
| Failed | 至少一个容器以非 0 退出且不再重启 | 任务失败 |
| Unknown | 无法获取状态 | 节点失联 |
二、容器状态(更常用)
bash
kubectl get pod -o custom-columns=NAME:.metadata.name,STATE:.status.containerStatuses[0].state1
- Waiting:等待中,
reason给出原因,如ImagePullBackOff、CrashLoopBackOff、ContainerCreating。 - Running:运行中,看
ready是否为 true(探针是否通过)。 - Terminated:已退出,
exitCode非零即失败,reason为Error或OOMKilled。
三、restartPolicy 三种取值
yaml
apiVersion: v1
kind: Pod
metadata:
name: demo-restart
spec:
restartPolicy: OnFailure # Always | OnFailure | Never
containers:
- name: c
image: busybox
command: ["sh", "-c", "exit 1"]1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
| 策略 | 行为 | 适用 |
|---|---|---|
Always | 无论退出码都重启(Deployment 默认且唯一允许值) | 长驻服务 |
OnFailure | 仅退出码非 0 时重启 | Job 任务 |
Never | 从不重启 | 一次性任务 |
注意
Deployment / ReplicaSet 管理的 Pod 只能用 Always,写 Never 会直接报校验错误。想让任务不重试请用 Job。
四、CrashLoopBackOff 的处理
bash
kubectl get pod demo-restart
kubectl describe pod demo-restart # 看 Last State 的 Exit Code
kubectl logs demo-restart --previous # 看上一次崩溃日志1
2
3
2
3
K8s 的重启退避是 10s、20s、40s… 上限 5 分钟,所以会看到间隔越来越长的重启。
五、优雅退出(graceful shutdown)
yaml
spec:
terminationGracePeriodSeconds: 60 # 默认 30
containers:
- name: app
image: nginx:alpine
lifecycle:
preStop:
exec:
command: ["sh", "-c", "sleep 10"]1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
删除 Pod 的流程:
- Pod 进入
Terminating,从 Service 的 Endpoints 摘除(不再接新流量); - 执行
preStop钩子; - 发送
SIGTERM给容器主进程; - 等待
terminationGracePeriodSeconds; - 超时则发
SIGKILL强杀。
建议
应用必须正确处理 SIGTERM(保存状态、关闭连接)。如果收到信号就立即退出,滚动更新时会出现请求中断。
六、Init 容器
yaml
spec:
initContainers:
- name: wait-db
image: busybox
command: ["sh", "-c", "until nslookup mysql; do echo waiting; sleep 2; done"]
containers:
- name: app
image: nginx:alpine1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Init 容器按序执行且必须全部成功后主容器才启动,适合做依赖等待、初始化数据、下载配置。
七、强制删除卡住的 Pod
bash
kubectl delete pod <pod名> --force --grace-period=01
验证
- [ ] 用
restartPolicy: Never的 Pod 退出后状态为Failed且不再重启 - [ ]
kubectl get pod能读到 CrashLoopBackOff 并用--previous看到日志 - [ ] 带 Init 容器的 Pod 在依赖未就绪时卡在
Init:0/1
常见坑
CrashLoopBackOff一直查不出原因:忘了加--previous,只看当前容器日志永远是空的。- Pod 卡在 Terminating:节点 kubelet 失联或容器进程不响应 SIGTERM,需
kubectl delete pod <pod> --force --grace-period=0。 - 滚动更新时请求 502:Pod 已杀但 Service/Ingress 摘流有延迟,加
preStop sleep可缓解。 - 改
restartPolicy不生效:该字段 Pod 创建后不可变更,必须重建 Pod。 - Init 容器失败导致 Pod 一直
Init:Error:用kubectl logs <pod> -c <init容器名>单独查看。