探针真正解决的问题,不是“进程活没活着”,而是“这个 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
排探针时我一般会连着问三件事:
- 探针到底在检查什么?
- 在容器内部能不能手工访问这个检查点?
- 当前失败是启动时机问题、应用逻辑问题,还是依赖波动问题?
探针怎么选的一个简单表
| 场景 | 更适合的探针 |
|---|---|
| 应用启动慢 | 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 文章
收个尾
好的探针设计通常没什么存在感。真正危险的反而是那些“特别聪明、特别严格、特别灵敏”的探针,因为它们很容易在真正有压力的时候变成事故的一部分。