探针不是“越多越好”
在 Kubernetes 中,kubelet 通过三类探针判断容器状态:livenessProbe(存活探针)、readinessProbe(就绪探针)、startupProbe(启动探针)。很多线上故障并非探针缺失,而是职责用错:把就绪探针当成存活探针、给慢启动服务只配存活探针、把探针指向依赖服务的接口等。理解它们的边界,比盲目加探针更重要。
三类探针的职责边界
- 存活探针:回答“这个容器还需要继续运行吗”。失败时 kubelet 会重启容器。它只应检查进程自身是否健康,不应检查外部依赖。
- 就绪探针:回答“这个容器现在可以接收流量吗”。失败时从 Service 的 Endpoints 中摘除,不重启容器。适合检查依赖是否就绪、预热是否完成。
- 启动探针:回答“容器是否已经启动完成”。在启动探针成功之前,存活和就绪探针不会生效,从而避免慢启动应用被存活探针反复重启。
一句话记忆:存活管重启,就绪管流量,启动管宽限。
常见配错与后果
- 存活探针检查数据库/下游接口:下游抖动会让所有 Pod 同时被重启,形成雪崩。正确做法是把依赖检查放在就绪探针。
- 慢启动服务只配存活探针:initialDelaySeconds 设短了会被反复杀死,设长了又会掩盖真实故障。应改用 startupProbe(failureThreshold × periodSeconds 决定最长启动时间)。
- 就绪探针过于严格:把非关键依赖也纳入检查,依赖一抖动就全量摘流,容量骤降。
- 探针超时/阈值过紧:网络抖动或 GC 停顿就触发失败,造成不必要的重启与摘流。
- 探针端口或路径写错:探针永远失败,Pod 陷入重启循环或始终 NotReady。
可验证的配置要点
三类探针都支持 httpGet、tcpSocket、exec、grpc 四种探测方式,共有字段包括:
initialDelaySeconds:容器启动后等待多久开始探测periodSeconds:探测间隔,默认 10 秒timeoutSeconds:单次探测超时,默认 1 秒successThreshold:连续成功多少次视为成功,默认 1failureThreshold:连续失败多少次视为失败,默认 3
注意:successThreshold 在存活探针中必须为 1。
一个典型组合如下(字段名与语义可在 Kubernetes 官方文档 “Configure Liveness, Readiness and Startup Probes” 中核对):
startupProbe:
httpGet: { path: /healthz, port: 8080 }
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet: { path: /healthz, port: 8080 }
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet: { path: /ready, port: 8080 }
periodSeconds: 5
failureThreshold: 3
含义:启动最多容忍 300 秒;之后每 10 秒探活,连续 3 次失败重启;就绪每 5 秒检查,失败即摘流。
实践建议
- 存活探针只暴露“进程内部健康”的接口,不查外部依赖。
- 依赖检查、预热完成放到就绪探针。
- 启动慢的服务优先用 startupProbe,而不是把 initialDelaySeconds 调大。
- 阈值要结合服务 P99 响应时间与 GC 特性设定,避免过紧。
- 上线前用
kubectl describe pod查看探针失败事件,确认失败原因符合预期。
探针的目标是提升可用性,不是增加配置项。先想清楚“失败后希望系统做什么”,再决定用哪一种探针。