探针真正解决的问题,不是“进程活没活着”,而是“这个 Pod 现在能不能安全接流量”“现在是不是应该重启”“启动慢到底算不算故障”。很多线上发布问题,看起来像是应用不稳定,实际根因往往是探针设计不合理。

三类探针分别负责什么

  • readiness:这个 Pod 现在能不能接流量?
  • liveness:这个容器是不是应该被重启?
  • startup:启动期间要不要暂时保护它,避免过早被判失败?

readiness 是流量闸门,liveness 是重启开关,startup 是慢启动保护层。

最小示例

readinessProbe:
  httpGet:
    path: /readyz
    port: 8080
  periodSeconds: 5
livenessProbe:
  httpGet:
    path: /livez
    port: 8080
  periodSeconds: 10
startupProbe:
  httpGet:
    path: /startupz
    port: 8080
  periodSeconds: 5
  failureThreshold: 24

每种探针到底应该测什么

Readiness

readiness 应该回答:这个服务现在能不能安全接请求?

适合当 readiness 信号的通常包括:

  • 应用监听已经建立
  • 必要依赖已经准备好到足以服务请求
  • 预热、缓存加载、迁移等启动动作已完成

不适合的包括:

  • 把所有外部依赖都绑进一个过深的检查
  • 检查逻辑本身就很重,反过来给服务制造负担

Liveness

liveness 应该只在“重启真的有帮助”时使用。

适合的场景:

  • 死锁
  • 主循环卡死
  • 进程还在,但功能上已经彻底挂住

不适合的场景:

  • 下游服务短暂抖动
  • 启动慢
  • 偶发 CPU 抖动或 GC 停顿

如果重启并不能帮你恢复,那 liveness 很可能就是错的。

Startup

startupProbe 很适合启动慢的服务。它能在启动阶段先拦住 readiness 和 liveness,避免服务刚起步就被误杀。

相比拍脑袋把 initialDelaySeconds 调得很大,startupProbe 通常是更稳的方案。

最常见的错误配置

把 liveness 当成流量开关

这是最贵的错误之一。如果你的目的只是暂时别接流量,那应该靠 readiness,而不是 liveness。否则一个暂时性问题就可能被你放大成重启风暴。

readiness 过于严格

如果 readiness 把所有非关键依赖都算进去,服务会因为一些本不该挡流量的小问题长期不进 endpoints。

timeout 和 failureThreshold 太激进

在空闲测试环境里看起来没问题,到了真实负载下一下就误判。探针参数应该反映真实延迟和真实启动过程,而不是理想状态。

探针参数怎么调

调探针不要照抄别人配置,先看你的工作负载特性:

  • periodSeconds:多久检查一次
  • timeoutSeconds:单次等多久
  • failureThreshold:失败几次才行动
  • successThreshold:成功几次才恢复 ready

对多数线上服务来说,略保守的参数往往比“反应特别快”的参数更稳。

为什么探针会直接影响发布

Deployment 能不能平稳 rollout,很大程度上依赖 readiness。只要 readiness 不合理,就可能出现:

  • rollout 卡住
  • 旧版本迟迟不下线
  • Service endpoints 抖动
  • 健康实例长时间不接流量

所以很多“发布问题”其实根本不是 Deployment 的问题,而是探针设计问题。

探针和优雅关闭要一起看

探针不是孤立存在的,它必须和终止流程配合起来:

  • 先让 readiness 把新流量挡住
  • 给足 terminationGracePeriodSeconds
  • 正确处理 SIGTERM
  • 避免 Pod 还在清理请求时就被硬杀

否则即便 readiness 看起来没错,发布时也仍然可能打出 502 或连接中断。

一套实用排障路径

kubectl describe pod demo-app -n demo
kubectl logs demo-app -n demo --tail=200
kubectl exec -it demo-app -n demo -- sh

排探针时我一般会连着问三件事:

  1. 探针到底在检查什么?
  2. 在容器内部能不能手工访问这个检查点?
  3. 当前失败是启动时机问题、应用逻辑问题,还是依赖波动问题?

探针怎么选的一个简单表

场景 更适合的探针
应用启动慢 startupProbe
暂时不要接流量 readinessProbe
进程已经卡死,重启能恢复 livenessProbe
下游依赖波动 通常优先考虑 readiness,不是 liveness

什么检查不适合直接做成探针

尽量避免把以下逻辑直接塞进探针:

  • 过深的业务链路检查
  • 很重的数据库查询
  • 依赖一堆外部系统的检查

探针应该有判断力,但不应该太戏剧化。

FAQ

Q: readiness 和 liveness 可以共用一个接口吗? A: 通常不建议。两者回答的问题不同,混在一起经常会把“流量控制”和“是否重启”搅成一团。

Q: 什么时候该加 startupProbe? A: 当服务启动时间明显较长,或者一开始就容易被 readiness / liveness 提前误判时。

Q: 为什么 Pod 明明 Running,却一直不接流量? A: 很常见的原因是 readiness 没通过。进程活着,不代表 Kubernetes 认为它现在适合接请求。

下一步阅读

  • 接着读 kubernetes-quickstart-deployment-replicaset.md
  • 再读 kubernetes-quickstart-service.md
  • 如果你想看更偏生产的经验,继续读 probes 的 tips 文章

收个尾

好的探针设计通常没什么存在感。真正危险的反而是那些“特别聪明、特别严格、特别灵敏”的探针,因为它们很容易在真正有压力的时候变成事故的一部分。

参考链接