如何配置 Kubernetes livenessProbe 存活探针避免容器被频繁重启?

文章导读
容器被频繁重启,先不要急着调大探针阈值,先用 kubectl describe pod 看 events。如果出现 liveness probe failed,说明探针已经判定容器不健康。探针参数只是表面因素,真正决定重启是否频繁的是探测路径的设计和应用的启动行为。下面按配置顺序逐步排查。
📋 目录
  1. 先想清楚探针要保护什么
  2. 启动等待和探测超时别混为一谈
  3. 频率和阈值需要配合应用行为调整
  4. exec 探针的额外代价
  5. 调整配置后的观察与回滚边界
A A

容器被频繁重启,先不要急着调大探针阈值,先用 kubectl describe pod 看 events。如果出现 liveness probe failed,说明探针已经判定容器不健康。探针参数只是表面因素,真正决定重启是否频繁的是探测路径的设计和应用的启动行为。下面按配置顺序逐步排查。

先想清楚探针要保护什么

存活探针的作用是识别无法自行恢复的进程状态,例如死锁或内存泄漏,而不是判断容器是否过载。配置时首先要明确探测接口的语义:它应返回当前进程的核心健康状态,不应依赖数据库、缓存等外部组件,否则网络抖动会导致探针失败,进而触发重启。一个常见的做法是暴露独立的 /healthz 端点,由应用自身检查关键协程或队列是否仍能推进,而不是直接返回 HTTP 200。

所以探测接口不能随手拿一个业务接口代替。有些应用会拿根路径 / 做健康检查,但根路径可能只是静态响应,无法反映进程内部状态。更稳妥的做法是单独实现一个 /healthz,在接口内部检查关键队列消费进度、最近一次定时任务执行时间或依赖连接池状态。注意,这里说的是“关键状态”,不是每次请求都去访问数据库,那样会把外部抖动引入探针。

启动等待和探测超时别混为一谈

在创建 Deployment 时,应设置 initialDelaySeconds 为应用平均启动时间再加缓冲,比如 10 秒或更长。如果启动时间本来就波动,可以用 startupProbe 预热,避免 livenessProbe 在启动阶段误杀。同时,timeoutSeconds 要大于探测请求的最大处理时间,通常 1 到 2 秒足够,但若接口内部有较重逻辑,可以放宽到 5 秒。设置过短会导致慢响应被判定为失败,过高则掩盖了实际的卡顿。

这里有个容易忽略的点:initialDelaySeconds 是容器启动后等待探针的秒数,它不包含镜像拉取时间。如果你的应用启动时间平均在 15 秒左右,initialDelaySeconds 可以设到 20 到 25 秒。同时,startupProbe 独立于 livenessProbe,它会一直探测直到成功,然后把控制权交给 livenessProbe。所以如果应用启动阶段存在慢依赖,优先用 startupProbe 而不是把 livenessProbe 的 failureThreshold 调得很高。下面是一个常见的 httpGet 探针配置,可以结合项目情况调整:

如何配置 Kubernetes livenessProbe 存活探针避免容器被频繁重启?
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 20
  timeoutSeconds: 2
  periodSeconds: 10
  failureThreshold: 3

频率和阈值需要配合应用行为调整

periodSeconds 控制两次探测之间的间隔,failureThreshold 控制连续失败多少次后重启。两者相乘约等于从第一次失败到触发重启的最短时间。比如 periodSeconds=10、failureThreshold=3,那么连续失败 30 秒左右才会重启。如果你的应用在流量高峰会偶尔出现几秒的慢响应,可以把 failureThreshold 调到 5,但不要调到 1。单次网络超时就重启,只会让副本被频繁杀掉,放大故障。反过来,periodSeconds 也不宜小于 5 秒,因为每个副本都会按这个频率请求健康接口,过密的探测会消耗额外 CPU 和连接数。建议的起点是 periodSeconds=10、failureThreshold=3、timeoutSeconds=2,然后根据实际日志微调。调参数时要注意,failureThreshold 是“连续”失败次数,不连续失败会计数清零。

exec 探针的额外代价

如果你用的是 exec 探针,先确认容器镜像里有没有 curl、wget 或可用的 shell。精简镜像经常只包含 busybox,有时连 bash 都没有。exec 探针每次探测都会拉起一个进程,频率越高开销越大。更隐蔽的问题是,探针命令可能依赖环境变量或外部服务,一旦这些变量或服务抖动,探针就会失败,实际上和业务故障混在一起。如果必须用 exec,先在容器里手动运行一遍,观察返回码。另外可以考虑用 httpGet 或 tcpSocket 探针,httpGet 还能直接利用 HTTP 状态码,并拥有独立的超时控制,通常比 exec 更可控。

调整配置后的观察与回滚边界

当容器频繁被重启时,先执行 kubectl describe pod 查看最近的事件,liveness probe failed 的错误会记录在 events 中。再通过 kubectl logs 查看重启前的应用日志,定位是探针超时还是应用真的陷入异常。调整配置后,建议观察至少两倍的 periodSeconds 与 failureThreshold 乘积时间,确认没有新的重启。注意,直接修改探针参数会触发滚动更新,如果有多个副本,先在测试环境验证,避免影响线上可用性。

这里要注意,观察时间不是只看新副本是否启动成功,而是要看它是否稳定运行。比如 periodSeconds=10、failureThreshold=3,至少观察 60 秒以上,最好跨过一整轮探针周期。另外,如果新配置导致新副本一直探测失败,kubectl rollout status 会卡住,这时需要 kubectl rollout undo 回滚到上一个 Deployment 版本。不要直接再改一遍参数去救火,先回滚再调参。