CFN Cloud
Cloud Future New Life
en zh
2025-12-29 · 0 次浏览

Kubernetes Tips:Readiness / Liveness / Startup 探针怎么用

用对探针,避免 CrashLoop 与糟糕的发布;读懂 readiness、liveness、startup 的职责与调参方法。

探针(Probes)决定了:

  • Pod 是否 接收流量(readiness)
  • 容器是否会被 自动重启(liveness)
  • 启动慢的服务是否会被 过早判死(startup)

很多“发布一上来就抖/经常重启”的问题,本质上不是业务逻辑崩,而是探针语义用错了。

心智模型(最重要的三句话)

  • Readiness:现在适合接流量吗?
  • Liveness:进程是不是卡死/不可恢复,需要重启吗?
  • Startup:启动期给我额外时间,先别用 liveness 折腾我。

最常见的坑:用 liveness 充当“流量开关”

如果你把 liveness 当成“没 ready 就死给你看”,你会得到:

  • 还在 warmup 或迁移的 Pod 被不断重启
  • 发布速度变慢,错误率变高
  • 甚至形成“重启风暴”

正确做法:

  • readiness 把 Pod 从 Service endpoints 中移除(不接流量)
  • startupProbe 保护启动期
  • liveness 只处理“重启能解决的卡死/异常”

一个靠谱的默认配置(HTTP 服务)

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30
  periodSeconds: 2

readinessProbe:
  httpGet:
    path: /readyz
    port: 8080
  periodSeconds: 5
  timeoutSeconds: 2
  failureThreshold: 3

livenessProbe:
  httpGet:
    path: /livez
    port: 8080
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3

这套配置的核心是:启动期先过 startup,再谈 liveness;流量交给 readiness 控制。

/readyz、/livez 应该检查什么

/readyz:能否正确服务请求(“现在”)

readiness 应该在以下场景失败:

  • 依赖还没连上(DB、缓存、上游服务)
  • 迁移未完成(但你又不希望接流量)
  • 预热未完成(关键缓存/配置未加载)

readiness 的本质是“业务可用性”,不是“进程是否活着”。

/livez:进程是否卡死/不可恢复(“重启能救”)

liveness 适合检查:

  • 死锁/事件循环卡死
  • 内部状态不可恢复(严重异常)

不推荐:把 DB 可用性作为 liveness 的硬条件。DB 抖一下你就把所有 Pod 重启一遍,往往会把事故扩大。

探针类型:HTTP / TCP / exec(用得越简单越好)

Kubernetes 支持:

  • httpGet:最推荐(语义清晰、可观测)
  • tcpSocket:只检查端口是否能连(语义弱)
  • exec:在容器里跑命令(灵活但可能昂贵)

建议:

  • 优先 HTTP endpoints
  • TCP 只作为无 HTTP 的兜底
  • exec 慎用(集群大了会变成“定时在所有 Pod 内执行脚本”,成本和风险都更高)

startupProbe 比 initialDelaySeconds 更靠谱

传统做法用 initialDelaySeconds 延迟探针启动,但缺点明显:

  • 延迟是固定值,启动快也要等
  • 启动慢超过延迟就被误判

startupProbe 更智能:

  • 在 startupProbe 成功之前,liveness 不会生效
  • 启动快就快通过,启动慢就给时间

实用换算:

最长允许启动时间 ≈ failureThreshold * periodSeconds

例如希望给 60 秒启动窗口,可以:

  • periodSeconds: 2
  • failureThreshold: 30

发布友好视角(Mermaid)

flowchart LR A[Pod 启动] --> B{startupProbe 通过?} B -- 否 --> A B -- 是 --> C{readiness 通过?} C -- 否 --> D[不接流量] C -- 是 --> E[接收流量] E --> F{liveness 通过?} F -- 否 --> A F -- 是 --> E

与优雅下线配合(否则探针也救不了)

探针只决定“是否在 endpoints 里”,但如果 Pod 退出太粗暴,还是会有错误。

建议:

  • 合理设置 terminationGracePeriodSeconds
  • 收到 SIGTERM 立即让 readiness 失败(快速摘流量)
  • 等待 in-flight 请求完成后再退出
  • 必要时加 preStop 做 drain/flush

调参避免抖动(timeout/threshold/period)

常见问题:

  • timeoutSeconds 太小(真实 p99 可能 > 1s)
  • periodSeconds 太密(探针负担大,反而影响业务)
  • failureThreshold 太小(一次抖动就摘流量/重启)

实践经验:

  • readiness:period 5stimeout 1-2sfailureThreshold 3
  • liveness:period 10stimeout 1-2sfailureThreshold 3
  • startup:按启动最长时间换算

排查探针失败(必备命令)

kubectl describe pod <pod>
kubectl logs <pod> -c <container> --previous
kubectl get events -n <ns> --sort-by=.lastTimestamp

在容器内部验证:

kubectl exec -n <ns> -it <pod> -- sh
curl -sS -i http://127.0.0.1:8080/readyz

如果镜像是 distroless 没有工具,用 ephemeral container(kubectl debug)来跑 curl 更安全。

可观测性建议:让 readiness 失败有“原因”

即使探针只看状态码,你也应该在服务内部记录:

  • 哪个依赖导致 readiness 失败
  • 失败次数与持续时间
  • 失败发生在发布/扩容/依赖抖动的哪个阶段

这样你才能把“探针失败”从现象变成可行动的根因。

Checklist

  • 启动慢的服务启用 startupProbe
  • readiness 控制接流量,liveness 控制重启
  • liveness 不依赖外部依赖(避免重启风暴)
  • timeouts/thresholds/period 贴近真实延迟分布
  • 下线流程与 readiness 配合(优雅摘流量)

参考链接

FAQ

Q: readiness 和 liveness 要用同一个接口吗? A: 通常不建议。readiness 关注依赖与可接流量,liveness 只需要快速判断是否“卡死”。

Q: 启动很慢怎么办? A:startupProbe,或提高 failureThreshold/period,别用很长的 initialDelaySeconds。

Q: readiness 失败会重启吗? A: 不会。只有 liveness 失败才会触发重启。