Skip to content

Pod 生命周期

Pod 是 Kubernetes 最小调度单元——一个或多个容器的组合,共享网络命名空间和存储卷。排查 K8s 服务时,Pod 是从"期望状态"到"实际运行进程"之间的关键环节:是否被调度、是否拉动镜像、是否挂载成功、容器是否启动、探针是否通过、退出后是否重启。

Pod 从创建到运行

每个阶段都可能卡住,对应的排查入口不同:

阶段说明这个阶段特有的问题
Pending尚未完成调度或依赖准备资源不足、污点没容忍、PVC 未绑定
ContainerCreating节点正在创建容器和网络拉镜像失败、挂载卷失败、CNI 分配 IP 失败
Running至少一个容器在运行容器进程在跑,但不等于业务可用
Succeeded所有容器正常结束Job 类工作负载的终点
Failed容器异常结束且不再重启退出码非 0、OOM、restartPolicy 相关

Running 只是容器进程在跑。Service 是否接流量看 readinessProbe。

initContainer

initContainer 在业务容器之前执行,全部成功后才会启动普通容器。

不用 initContainer 时,应用容器要自己处理"等数据库就绪、初始化目录、生成配置"这些前置动作——启动脚本里塞满 sleepuntil nc -z。initContainer 把这些前置逻辑从应用镜像里分离出来,按顺序执行,且每个 initContainer 可以用不同镜像和工具。

yaml
apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  initContainers:
    - name: wait-db
      image: busybox:1.36
      command: ["sh", "-c", "until nc -z mysql 3306; do sleep 2; done"]
  containers:
    - name: app
      image: nginx:1.26

initContainer 失败时 Pod 处于 Init:ErrorInit:CrashLoopBackOff,不会进入 ContainerCreating 阶段。initContainer 按顺序执行——第一个成功后才跑第二个,全部成功后才启动业务容器。只保证顺序,不保证幂等——数据库 schema 迁移这类操作放在 initContainer 里时,需要单独处理重复执行和失败重试。

重启策略

Pod 级别 restartPolicy 决定容器退出后 kubelet 的行为:

策略含义哪里用
Always容器退出后总是重启Deployment、StatefulSet、DaemonSet 默认
OnFailure非 0 退出码才重启Job 常见
Never退出后不重启一次性 Job、初始化 Pod

Deployment 的 Pod 默认 Always——应用进程退出后 kubelet 重新拉起来。但 Always 不等于"无限重试"——连续失败后会进入 CrashLoopBackOff,每次重启间隔逐渐拉长(指数退避,最长 5 分钟)。

三种探针

探针解决的问题失败后果
startupProbe应用启动慢——启动窗口内不触发 liveness 误杀超过 failureThreshold 后 kubelet 重启容器
readinessProbe应用在跑但暂时接不了流量——缓存没热、连接没建好从 Service 后端摘除,不影响容器进程
livenessProbe应用进程在但实际已经僵死——死锁、死循环、内存泄漏失败后 kubelet 重启容器

先从最简 Deployment(无探针)开始:

yaml
containers:
  - name: app
    image: harbor.example.com/app:v1
    ports:
      - containerPort: 8080

没有探针时,容器进程一启动就被认为 Ready,流量立刻打进来。启动慢的服务——Java、需要预热缓存、连接池初始化——会在还没准备好时收到请求,返回 5xx。

加上 startupProbe 保护启动窗口:

yaml
startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30   # 最多等 30 × periodSeconds = 60 秒
  periodSeconds: 2

startupProbe 存在期间,livenessProbe 和 readinessProbe 不生效。startupProbe 成功后,另外两个探针接管。启动慢但 startupProbe 没配或 failureThreshold 太小——应用还在初始化,liveness 已经判定失败——容易出现"容器反复重启"。

加上 readinessProbe 控制流量接入:

yaml
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  periodSeconds: 5
  failureThreshold: 3    # 连续失败 3 × 5 = 15 秒后摘除

readinessProbe 失败后 Pod 从 Service EndpointSlice 里移除,不再接收流量——容器进程不受影响,不会被杀掉。恢复后探针通过,Pod 重新加入 Service 后端。滚动更新时,新 Pod 的 readinessProbe 通过之前旧 Pod 不会删除,更新节奏由探针驱动。

加上 livenessProbe 处理僵死:

yaml
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  failureThreshold: 3

livenessProbe 是修复手段——容器僵死后 kubelet 重启它。不要因为外部依赖(数据库、Redis、第三方 API)不可用就判定 liveness 失败——重启应用容器并不能修复外部依赖,反而可能把重启雪崩扩散出去。

容器状态和退出信息

bash
kubectl get pod <pod-name> -n <namespace> -o wide
kubectl describe pod <pod-name> -n <namespace>
kubectl get pod <pod-name> -n <namespace> \
  -o jsonpath='{.status.containerStatuses[*].state}{"\n"}'
状态说明
Waiting等待中——拉镜像、等待创建、restartPolicy 退避
Running容器进程运行中
Terminated容器已退出——有 exitCode、reason、startedAt、finishedAt

上一次退出原因:

bash
kubectl get pod <pod-name> -n <namespace> \
  -o jsonpath='{.status.containerStatuses[0].lastState.terminated}{"\n"}'

日志和事件

bash
kubectl logs <pod-name> -n <namespace>
kubectl logs <pod-name> -n <namespace> --previous   # 上一次崩溃前的日志
kubectl logs <pod-name> -n <namespace> -c <container-name>   # 多容器 Pod 指定容器
kubectl get events -n <namespace> --sort-by=.lastTimestamp

Events 偏平台动作(调度、拉镜像、挂载卷),日志偏应用进程。这两层的关系:Events 说 Pod 在哪个阶段卡住了(仍在 ContainerCreating → 还没到应用层面);日志说在启动后发生了什么(应用报错连不上数据库 → 平台层没问题,是应用配置)。平台还没把容器启动起来时,应用日志是空的——先看 Events。

常见状态处理

状态常见原因先看什么
Pending调度失败、PVC 未绑定describe pod → Events,节点资源,PVC 状态
ImagePullBackOff镜像名写错、仓库认证、网络Events、节点 crictl pull
ContainerCreatingCNI 分配 IP、挂载卷、sandbox 创建Events、kubelet 日志
CrashLoopBackOff程序启动后退出logs --previous、exitCode、启动命令
OOMKilled内存超过 limit容器 lastState、limit 配置、应用内存曲线