IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。
在第 21 篇中,我们编写了 Pod YAML,部署了包含 Flask 和 Redis 的双容器 Pod,体验了共享网络和 localhost 互访。但关于 Pod,还有几个关键问题没有回答:Pod 从创建到销毁经历了哪些阶段?Pending 和 Running 之间发生了什么?容器退出了,Pod 为什么还在?RESTARTS 列的数字是谁在控制?
回想第 6 篇,我们学容器生命周期时,Docker 容器的状态流转相对简单------created → running → paused → exited → deleted。而 K8s 的 Pod 生命周期在此基础上增加了更多阶段,并引入了重启策略 来定义"容器退出后该怎么办"。今天这篇就是要把这些规则彻底搞清楚,同时引出Init Container这个启动前置机制,为第 24 篇的探针健康检查做好铺垫。
一、Pod 生命周期的完整阶段
1.1 生命周期全景图
一个 Pod 从创建到销毁,会经历以下阶段:
bash
┌─────────────┐
│ Pending │ ← 已提交,等待调度 + 拉取镜像
└──────┬──────┘
│ 调度成功 + 镜像拉取完成
┌──────▼──────┐
│ Running │ ← 至少一个容器在运行
└──────┬──────┘
│
┌──────────────────┼──────────────────┐
│ │ │
┌───────▼──────┐ ┌───────▼──────┐ ┌───────▼──────┐
│ Succeeded │ │ Failed │ │ Unknown │
│ 正常退出码0 │ │ 非零退出码 │ │ 节点失联等 │
└──────────────┘ └──────────────┘ └──────────────┘
-
Pending:Pod 已被 API Server 接受并写入 etcd,但尚未在任何节点上运行。这个阶段包含 Scheduler 选择节点、kubelet 拉取镜像的过程。如果 Pod 长时间卡在 Pending,通常是因为资源不足或镜像拉取失败。
-
Running:Pod 已被调度到节点,所有容器创建完成,至少有一个容器仍在运行(未退出)。
-
Succeeded:Pod 内所有容器都已正常终止(退出码为 0),且不会再重启。典型场景是一次性 Job。
-
Failed:Pod 内至少有一个容器以非零退出码终止,且不会再重启。
-
Unknown:Pod 状态无法获取,通常是因为 Pod 所在节点失联(网络分区、节点宕机)。
1.2 动手观察:Pod 的状态变化
部署一个临时 Pod,观察它的状态变化过程:
bash
kubectl run lifecycle-demo --image=nginx:alpine --restart=Never
用 -w 持续观察:
bash
kubectl get pod lifecycle-demo -w
输出:
bash
NAME READY STATUS RESTARTS AGE
lifecycle-demo 0/1 Pending 0 0s
lifecycle-demo 0/1 ContainerCreating 0 1s
lifecycle-demo 1/1 Running 0 5s
ContainerCreating 不是官方 Pod 阶段之一,而是 kubectl 在 Pending 阶段中展示的过渡状态------kubelet 正在拉取镜像并创建容器。如果镜像较大或网络较慢,这个过渡状态会持续更长时间。
1.3 Pod 状态 vs 容器状态
Pod 状态和容器状态是两个不同的概念,这一点经常被混淆:
-
Pod Status:由 kubelet 汇总所有容器状态后上报(Pending / Running / Succeeded / Failed / Unknown)
-
Container State:单个容器的具体状态(Waiting / Running / Terminated),受重启策略影响
可以通过 kubectl describe pod 查看每个容器的详细状态信息:
bash
kubectl describe pod lifecycle-demo | grep -A10 "Containers:"
1.4 容器终止流程与 TerminationGracePeriodSeconds
当 Pod 被删除时,K8s 会按照以下流程优雅终止容器:
-
Pod 进入
Terminating状态 -
kubelet 向每个容器的主进程发送 SIGTERM 信号
-
等待
terminationGracePeriodSeconds秒(默认 30 秒) -
如果容器仍未退出,kubelet 发送 SIGKILL 强制终止
-
从 API Server 中删除 Pod 对象
你可以在 Pod spec 中自定义这个宽限期:
bash
spec:
terminationGracePeriodSeconds: 60
这与 Docker 中 docker stop -t 30 的机制完全一致------先 SIGTERM 优雅退出,超时后 SIGKILL 强制终止。
二、重启策略:容器退出后怎么办?
K8s 提供了三种重启策略,用 restartPolicy 字段指定。这三种策略和 Docker 的 --restart 参数有对应关系,但适用层级不同------Docker 的 restart 作用于单个容器,而 K8s 的 restartPolicy 作用于 Pod 内的所有容器。
2.1 Always(默认值)
行为:容器退出(无论退出码是否为 0),kubelet 都会重启它。重启间隔由指数退避算法控制:首次重启立即执行,之后间隔 10 秒、20 秒、40 秒......,最长不超过 5 分钟,重置间隔需要容器正常运行至少 10 分钟。
适用场景 :长期运行的服务(Web 服务器、数据库、缓存),这是 Deployment、StatefulSet 等控制器创建 Pod 时强制使用的策略。
2.2 OnFailure
行为 :只有当容器以非零退出码退出时,才执行重启。容器正常退出(退出码 0)不会重启。
适用场景:Job 或 CronJob,批处理任务失败时需要重试,成功则停止。
2.3 Never
行为:容器退出后永不重启。
适用场景:一次性初始化任务(如数据库迁移),或用于调试的临时 Pod。
2.4 策略对比
2.5 动手验证:对比三种策略
Always(默认):
bash
# 创建一个 Pod,容器执行后立即退出(退出码 0)
kubectl run always-demo --image=alpine --restart=Always --command -- sh -c "echo 'done' && exit 0"
# 观察 RESTARTS 列
kubectl get pod always-demo -w
# NAME READY STATUS RESTARTS AGE
# always-demo 0/1 CrashLoopBackOff 3 90s
RESTARTS 数值不断增加------即使容器正常退出,Always 策略也会重启它。CrashLoopBackOff 是 kubelet 的一种保护机制:当容器在短时间内被反复重启,kubelet 会逐渐延长重启间隔,避免陷入无限重启循环消耗节点资源。
OnFailure:
bash
# 模拟失败:退出码 1
kubectl run onfailure-demo --image=alpine --restart=OnFailure --command -- sh -c "exit 1"
kubectl get pod onfailure-demo -w
# NAME READY STATUS RESTARTS AGE
# onfailure-demo 0/1 CrashLoopBackOff 3 90s
容器退出码非零,OnFailure 策略触发重启。
Never:
bash
# 正常退出
kubectl run never-demo --image=alpine --restart=Never --command -- sh -c "echo 'done'"
kubectl get pod never-demo
# NAME READY STATUS RESTARTS AGE
# never-demo 0/1 Completed 0 5s
STATUS=Completed,RESTARTS=0------容器退出后不再重启,Pod 进入 Succeeded 阶段。Completed 是 kubectl 对 Succeeded 阶段的展示名称。
2.6 清理实验 Pod
bash
kubectl delete pod lifecycle-demo always-demo onfailure-demo never-demo
三、Init Container:启动前置任务
3.1 什么是 Init Container?
在某些场景下,应用容器启动前需要先完成一些准备工作------等数据库就绪、下载配置文件、检查外部依赖。如果把重试逻辑写进应用代码会使应用变得复杂,K8s 提供的解决方案是 Init Container。
Init Container 是 Pod 中一种特殊的容器,它在应用容器启动之前 执行,并且必须成功完成(退出码 0)后,kubelet 才会启动应用容器。如果 Init Container 失败,kubelet 会根据 Pod 的重启策略决定是否重试。
Init Container 与普通容器的关键区别:
3.2 实战:等待 Redis 就绪的 Init Container
以下 YAML 定义了一个 Init Container,在应用启动前轮询 Redis 是否可用:
bash
apiVersion: v1
kind: Pod
metadata:
name: flask-with-init
spec:
restartPolicy: Always
initContainers:
- name: wait-for-redis
image: redis:alpine
command:
- sh
- -c
- |
echo "等待 Redis 就绪..."
until redis-cli -h redis-service -p 6379 ping; do
echo "Redis 尚未就绪,2 秒后重试..."
sleep 2
done
echo "Redis 已就绪!"
containers:
- name: flask-app
image: flask-redis-counter:2.0
ports:
- containerPort: 5000
env:
- name: REDIS_HOST
value: redis-service
- name: redis
image: redis:alpine
ports:
- containerPort: 6379
initContainers 字段与 containers 同级。这里定义的 wait-for-redis Init Container 会循环执行 redis-cli ping 直到成功,退出码 0 后 kubelet 才启动 Flask 容器。实际的 Redis 依赖应在 K8s 中用 Service 暴露------此时我们用 redis-service 指代这个 Service 名称。
3.3 执行流程追踪
部署这个 Pod 后查看事件:
bash
kubectl describe pod flask-with-init | grep -A5 "Events:"
输出会清晰展示 Init Container 的启动和执行过程。Init Container 常用于等待数据库、下载配置模板、设置文件权限等场景。如果应用本身已包含重试逻辑(比如我们 Flask 应用中连接 Redis 的 get_hit_count 函数),Init Container 并非必须,但在需要确保某个外部依赖完全就绪再启动的场景中,它是最简洁的 K8s 原生方案。
四、对比 Docker Compose 的启动控制
学到这里,做一个贯穿系列的知识串联。
第 15 篇我们学过 Compose 用 depends_on + condition: service_healthy 控制启动顺序。K8s 中实现相同效果的手段有三层:
-
Init Container :确保某个外部依赖(如数据库)可连接,再启动应用容器。对应 Compose 中
depends_on的条件等待。 -
Readiness Probe :告知 Service 该 Pod 是否可接收流量。对应 Compose 中
healthcheck的"可用性"判定(第 24 篇详解)。 -
Liveness Probe :检测容器是否处于死锁/假死状态,触发重启。对应 Compose 的
healthcheck配合restart策略(第 24 篇详解)。
五、命令速查表
六、本篇总结
-
Pod 生命周期五阶段:Pending → Running → Succeeded / Failed / Unknown,每个阶段有明确含义。
-
三种重启策略 :
Always(默认,服务类 Pod 必须使用)、OnFailure(批处理重试)、Never(一次性任务),控制容器退出后的行为。 -
TerminationGracePeriodSeconds:控制优雅终止的超时窗口(默认 30 秒),SIGTERM → 等待 → SIGKILL。
-
Init Container :在应用容器前执行的初始化任务,按顺序串行执行,全部成功后才启动普通容器。对应 Compose 的
depends_on逻辑。 -
CrashLoopBackOff:kubelet 的保护机制,容器反复重启触发指数退避。
这一篇让我们真正理解了 Pod 从创建到终止的完整过程,以及如何通过重启策略和 Init Container 控制容器行为。下一篇文章------第 23 篇:多容器 Pod 与设计模式(Sidecar 等),我们将深入 Pod 的常见设计模式,看看如何在实际项目中优雅地组织多容器 Pod。
想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !