路线图

健康检查与生命周期

星辉 2026-07-02 阅读 4 min 750 字 路线图
健康检查与生命周期 封面

概述#

Pod 从创建到终止是一个完整的生命周期:启动→运行→停止。在这个过程中,Kubernetes 提供了三类探针(Probe)来检查容器状态,以及 preStop Hook 和 terminationGracePeriodSeconds 来控制优雅退出。这些看似简单的配置,在生产环境中是避免"服务不健康却被分配流量""程序没启完就被杀掉""进程被强制 kill 丢数据"等问题的最基础保障。


Liveness Probe:容器该不该重启#

核心概念#

Liveness Probe 回答一个问题:容器里的进程还活着吗? 如果探针失败,kubelet 会杀死容器并根据 restartPolicy 决定是否重启。

它的职责是检测"死锁/卡死/不可恢复"的状态——比如 Java 应用 OOM 后线程僵死、进程还在但不再响应请求。

三种检测方式#

类型原理适用场景
HTTP发送 HTTP GET 请求,2xx/3xx 才算成功Web 服务最常用
TCP尝试 TCP 连接指定端口数据库、gRPC 等非 HTTP 服务
Exec在容器内执行命令,返回 0 才算成功需要自定义健康逻辑的场景

HTTP 探针示例#

yaml
livenessProbe:
  httpGet:
    path: /healthz          # 健康检查路径
    port: 8080              # 端口
    httpHeaders:            # 可选:自定义 Header
      - name: X-Check-Type
        value: liveness
  initialDelaySeconds: 30   # 容器启动后等 30 秒再开始检测
  periodSeconds: 10         # 每 10 秒检测一次
  timeoutSeconds: 5         # 每次检测的超时时间
  failureThreshold: 3       # 连续失败 3 次才判定为失败
  successThreshold: 1       # 成功 1 次即认为恢复

TCP 探针示例#

yaml
livenessProbe:
  tcpSocket:
    port: 6379              # 检测 Redis 端口是否可连接
  initialDelaySeconds: 15
  periodSeconds: 10
  failureThreshold: 3

Exec 探针示例#

yaml
livenessProbe:
  exec:
    command:
      - /bin/sh
      - -c
      - |
        # 自定义检查逻辑:检查进程是否存在 + 检查某个文件状态
        pgrep nginx && [ -f /tmp/healthy ]
  initialDelaySeconds: 10
  periodSeconds: 5
  failureThreshold: 3

常见坑点#

探针太激进是新手最常见的错误。如果 initialDelaySeconds 太短,应用还没启动完成就开始检测,会导致容器被反复误杀。

Liveness 不检查外部依赖——只检查容器自身状态,不要在 Liveness 里连数据库。如果数据库挂了,Liveness 把 Pod 杀了也解决不了问题,反而可能引发重启风暴。


Readiness Probe:是否接流量#

与 Liveness 的本质区别#

维度Liveness ProbeReadiness Probe
回答的问题容器还活着吗?容器能处理请求吗?
失败后果杀死容器并重启从 Service Endpoints 中摘除,不再接收流量
典型场景应用死锁、OOM 僵死应用启动中、临时过载、依赖未准备好
恢复后自行恢复或需要重启重新加入 Endpoints,恢复正常流量

一句话总结:Liveness 决定"该不该杀",Readiness 决定"该不该给流量"。

配置示例#

yaml
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5    # 启动后 5 秒开始检测(比 Liveness 短,尽早接流量)
  periodSeconds: 5          # 每 5 秒检测一次
  timeoutSeconds: 3
  failureThreshold: 3       # 连续失败 3 次摘除
  successThreshold: 1       # 成功 1 次即可加入

Readiness 的工作流程#

text
Pod 启动 → Readiness Probe 检测
  ├─ 失败 → Pod 被从 Service Endpoints 移除,不接用户流量
  └─ 成功 → Pod 加入 Endpoints,开始接收流量

运行时 → Readiness 周期性检测
  ├─ 失败 → 再次从 Endpoints 移除
  └─ 成功 → 重新加入 Endpoints

典型场景#

  • 应用启动后需要连接数据库、预热缓存——Readiness 在这些操作完成后再返回成功
  • 临时过载时需要停止新流量——应用主动让 /ready 返回 503,Kubernetes 自动摘除

Startup Probe:慢启动应用的救星#

解决的问题#

想象一个 Java 应用需要 90 秒才能完全启动。如果按照 Liveness 的常规配置 initialDelaySeconds: 30, periodSeconds: 10, failureThreshold: 3

text
0s  - 容器启动
30s - 第一次 Liveness 检测 → 还没起完 → 失败
40s - 第二次 → 失败
50s - 第三次 → 失败 → 连续 3 次失败 → 容器被杀!

明明再等 40 秒就启动完了,但容器被 Liveness 误杀了。

Startup Probe 的工作方式#

Startup Probe 和 Liveness/Readiness 是串行关系

text
容器启动
  → Startup Probe 检测(Liveness/Readiness 休眠)
  → Startup 成功后
  → Liveness 和 Readiness 接管

如果 Startup 失败了,容器会被重启(类似 Liveness)。但它给慢启动应用留出了充足的时间。

配置示例#

yaml
startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30      # 最多允许失败 30 次
  periodSeconds: 10         # 每 10 秒检测一次
  # total=30×10=300秒,给应用 5 分钟启动时间

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  failureThreshold: 3       # Startup 成功后,Liveness 恢复正常灵敏度

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  periodSeconds: 5
  failureThreshold: 3

关键是 Startup failureThreshold × periodSeconds = 你给应用的最长启动时间窗口。一旦启动成功,Liveness 就不用设那么长的 initialDelaySeconds

没有 Startup Probe 时怎么办#

如果没有 Startup Probe(Kubernetes 1.16 以前),只能把 Liveness 的 initialDelaySeconds 设得很大。但这意味着即使应用真正卡死后也要等很久才会被杀。Startup Probe 解决了这个矛盾。


preStop Hook:优雅退出#

核心概念#

preStop Hook 是容器停止前执行的最后一段命令。当 Pod 被删除时,流程如下:

text
1. Pod 进入 Terminating 状态(宽限期计时从这里开始)
2. preStop Hook 执行(如果配置了)
3. preStop 结束后,向容器主进程发送 SIGTERM
4. 直到 terminationGracePeriodSeconds(默认 30 秒,从第 1 步起算,preStop 也占用这段时间)耗尽
5. 如果还没退出,发送 SIGKILL 强制结束

典型用法:发送 deregister 信号#

微服务架构中,一个服务实例下线前需要从注册中心摘除自己,并等待正在处理的请求完成:

yaml
lifecycle:
  preStop:
    exec:
      command:
        - /bin/sh
        - -c
        - |
          # 1. 发送 deregister 信号到服务注册中心
          curl -X POST http://consul:8500/v1/agent/service/deregister/my-service-${HOSTNAME}
          # 2. 等待流量排空(给负载均衡器刷新时间)
          sleep 15

为什么需要 sleep?#

大多数负载均衡器(如 Ingress Controller、Service Endpoints)不是实时的——从 Pod 被从 Endpoints 移除到不再转发流量,有一个时间差。sleep 15 就是为这段时间留出缓冲,防止 Pod 在连接还没关闭时就被杀掉。

其他典型用法#

  • 数据库连接池优雅关闭
  • 消息队列 consumer 停止消费并处理完当前消息
  • 文件/缓冲区 flush 到存储

terminationGracePeriodSeconds:宽限时间窗口#

与 preStop 的配合关系#

terminationGracePeriodSeconds 定义的是从 Pod 进入 Terminating 状态到被强制 SIGKILL 的总时长。preStop Hook 的执行时间包含在这个窗口内。

text
terminationGracePeriodSeconds = 60秒

时间线:
0s  - Pod Terminating,preStop 开始执行
15s - preStop 完成(包含 sleep 15s)
15s - 主进程收到 SIGTERM
60s - 主进程还没退出 → SIGKILL 强制结束

如果 preStop 执行了 70 秒(超过了 60 秒的宽限),在 60 秒时 preStop 会被 SIGKILL,然后主进程也会被 SIGKILL。

配置示例#

yaml
spec:
  terminationGracePeriodSeconds: 60   # 给应用 60 秒优雅退出时间
  containers:
    - name: app
      lifecycle:
        preStop:
          exec:
            command:
              - /bin/sh
              - -c
              - |
                curl -X POST http://consul:8500/v1/agent/service/deregister/app-${HOSTNAME}
                sleep 15

值怎么定#

应用类型建议值原因
无状态 API30-60s处理在途 HTTP 请求 + LB 刷新
消息消费者60-120s需要时间处理完正在消费的消息
长时间任务根据任务最长执行时间不希望任务被 SIGKILL 打断
数据库120-300s需要 flush 缓冲区、关闭连接

三探针 + preStop 全配置示例#

yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-full-health
spec:
  terminationGracePeriodSeconds: 60
  containers:
    - name: app
      image: my-app:1.0
      ports:
        - containerPort: 8080
      resources:
        requests:
          cpu: "200m"
          memory: "256Mi"
        limits:
          cpu: "500m"
          memory: "512Mi"
      # 启动探针:给慢启动留时间
      startupProbe:
        httpGet:
          path: /healthz
          port: 8080
        failureThreshold: 30
        periodSeconds: 10
      # 就绪探针:控制流量接入
      readinessProbe:
        httpGet:
          path: /ready
          port: 8080
        periodSeconds: 5
        failureThreshold: 3
      # 存活探针:检测死锁
      livenessProbe:
        httpGet:
          path: /healthz
          port: 8080
        periodSeconds: 10
        failureThreshold: 5
      # 优雅退出
      lifecycle:
        preStop:
          exec:
            command:
              - /bin/sh
              - -c
              - |
                /app/deregister.sh && sleep 15

实战要点#

  1. 先有 Readiness,再有 Liveness:Readiness 是所有生产服务的必备项,Liveness 只在确实需要检测死锁时才加。
  2. Liveness 不要连外部依赖:连数据库失败的应该是 Readiness 管,不是 Liveness 管。Liveness 只检查自身进程状态。
  3. 慢启动应用必须配 Startup Probe:Java、Node.js 等启动慢的应用,没有 Startup Probe 迟早被 Liveness 误杀。
  4. preStop 配合 terminationGracePeriodSeconds:只配 preStop 不调宽限时间,如果 preStop 执行太久会被 SIGKILL 中断。
  5. 探针参数要保守failureThreshold 设大一点(3-5 次),periodSeconds 不要太小(5-10 秒),避免网络抖动导致误判。

小结#

三类探针各有分工:Startup 给慢启动应用缓冲,Liveness 检测死锁决定是否重启,Readiness 控制流量开关。preStop Hook 和 terminationGracePeriodSeconds 共同构成优雅退出机制——preStop 做清理和 deregister,宽限时间确保一切操作来得及完成。这些配置加在一起,就是让你的 Pod "该活的时候活着,该死的时候优雅地死"。