Kubernetes 探针实战:Liveness、Readiness 与 Startup 配置

在 Kubernetes 里,Kubernetes 探针(Probe)是 kubelet 用来判断容器“是否健康、是否能接流量、是否启动完成”的健康检查机制。合理配置 liveness、readiness 与 startup 三类探针,能在进程假死、依赖未就绪、慢启动等场景下自动重启或摘流,是生产级工作负载的标配。本文用可复制的 YAML 讲清三类探针的区别、三种探测方式,以及最常见的配置误区。

一、三类探针到底管什么

很多人把三种探针混用,结果要么被反复重启,要么流量打到了还没准备好的 Pod。三者的职责完全不同:

探针回答的问题失败后果典型用途
livenessProbe容器还活着吗?杀死并重启容器应对死锁、假死
readinessProbe容器能接流量吗?从 Service 端点摘除依赖就绪、预热完成
startupProbe容器启动完了吗?失败则重启(在它成功前不跑 liveness)慢启动应用

一句话记忆:liveness 决定“要不要杀”,readiness 决定“要不要给流量”,startup 决定“启动期先别急着杀”。三者可以共存于同一个容器。

二、Liveness 探针:容器假死的最后一道保险

livenessProbe 失败会触发 kubelet 重启容器。它适合检测“进程还在但已经无法服务”的死锁场景。最常见的探测方式有三种。

exec:在容器内执行命令

livenessProbe:
  exec:
    command:
    - /bin/sh
    - -c
    - test -f /tmp/healthy
  initialDelaySeconds: 5
  periodSeconds: 10

当 /tmp/healthy 文件不存在时,命令返回非 0,探测失败。一个经典误用是把“应用是否就绪”也塞进 liveness:一旦依赖的数据库连不上,liveness 失败导致容器被无限重启,反而雪上加霜。

httpGet:发起 HTTP 请求

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
    scheme: HTTP
  initialDelaySeconds: 10
  periodSeconds: 10
  timeoutSeconds: 2
  failureThreshold: 3

HTTP 探测返回 200–399 视为成功,其它状态码(含 500)都算失败。注意:不要把需要鉴权或依赖下游的接口当作 liveness 端点,否则一个下游抖动就会引发级联重启。

tcpSocket:仅检查端口是否可连通

readinessProbe:
  tcpSocket:
    port: 6379
  initialDelaySeconds: 5
  periodSeconds: 5

tcpSocket 只验证“端口能连上”,不验证业务逻辑,适合 Redis、MySQL 这类纯端口服务,但无法区分“连上了但已无法响应命令”。

三、Readiness 探针:流量准入的闸门

readinessProbe 失败不会重启容器,而是把 Pod 从对应 Service 的 endpoints 里摘掉,直到探测恢复。它用来表达“我现在还不能接流量”。

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 3
  periodSeconds: 5
  successThreshold: 1
  failureThreshold: 3

一个典型场景:应用启动后需要先加载模型、预热缓存、连上消息队列。这些没完成前,readiness 返回失败,Service 不会把请求转发过来,避免了“启动即报错”的流量黑洞。它与 K8s ConfigMap/Secret 实战 配合时,配置热更新后也可通过 readiness 短暂摘流再恢复。

四、Startup 探针:慢启动应用的救星

如果应用冷启动要 2 分钟(如 JVM 大堆、AI 模型加载),而 liveness 的 periodSeconds×failureThreshold 只有 30 秒,启动期就会被反复杀掉,永远起不来。startupProbe 就是为此而生:在它成功之前,liveness 与 readiness 不会生效。

startupProbe:
  httpGet:
    path: /healthz
    port: 8080
  failureThreshold: 30   # 每次 10s,最多等 300s
  periodSeconds: 10
livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  periodSeconds: 10
  failureThreshold: 3

这样 startup 给足 5 分钟启动窗口,启动成功后 liveness 才接管。Startup 探针与文件描述符耗尽排查这类资源类故障也常有关联:资源受限时启动明显变慢,正是 startup 阈值该放大的信号。

五、三种探测方式对照与选型

方式优点缺点适用
exec能验证任意内部状态要写脚本,较重复杂依赖检查
httpGet语义清晰,零依赖需暴露端点Web 服务首选
tcpSocket最轻量不验证业务逻辑纯端口服务

六、生产级参数清单

以下五个参数决定了探针的行为节奏,务必按应用实际调优,而不是全用默认值:

# 推荐基线(Web 服务)
livenessProbe:
  httpGet: { path: /healthz, port: 8080 }
  initialDelaySeconds: 15   # 启动后多久开始探
  periodSeconds: 10         # 探测间隔
  timeoutSeconds: 2         # 单次超时
  successThreshold: 1       # 连续几次成功算恢复
  failureThreshold: 3       # 连续几次失败算失败
参数含义经验值
initialDelaySeconds首次探测前的等待快应用 5–15s,慢应用配合 startup
periodSeconds探测周期5–15s
timeoutSeconds单次超时1–3s
failureThreshold失败容忍次数liveness 3,readiness 2–3
successThreshold恢复所需连续成功默认 1

七、一个真实事故:探针配错导致流量全挂

某次发布后,readiness 端点依赖了一个刚上线的内部鉴权服务。鉴权服务抖动时,所有 Pod 的 readiness 同时失败,Service endpoints 被清空,入口流量 100% 502。根因是把“强依赖外部服务”的逻辑放进了 readiness。修复方式是把 readiness 收敛为“仅检查本进程核心能力”,外部依赖交给RBAC 与重试与熔断处理。

八、与资源限制、优雅停机配合

探针不是孤立的。当容器因内存超限被 OOMKilled(见OOMKilled 排查实战)时,liveness 的重启会叠加在资源压力下,可能形成重启风暴。建议给容器设置合理的 resources.limits,并在应用里实现 SIGTERM 优雅停机:先让 readiness 失败摘流,再处理完在途请求后退出。同时配合 Pod 安全上下文 以非 root 运行,缩小爆炸半径。

九、常见误区排障表

现象原因修复
Pod 一直重启liveness 阈值太短 / 端点依赖外部拉长 failureThreshold,解耦外部依赖
新 Pod 启动即报错未配 startup,启动慢被 liveness 杀加 startupProbe 给足窗口
流量打到报错 Pod只配了 liveness 没配 readiness补 readiness 摘流
滚动更新卡住readiness 迟迟不成功检查就绪条件是否可达

十、落地 Checklist

项建议
Web 服务httpGet + 独立 /healthz、/ready 端点
纯端口服务tcpSocket 或 exec
慢启动必配 startupProbe
liveness只验证“进程还活着”,不依赖下游
readiness验证“能接流量”,依赖就绪前先摘流
参数显式设置 5 个节奏参数,拒绝全默认

十一、小结

Kubernetes 探针是性价比极高的稳定性投资:用几行 YAML 就把“自动重启、自动摘流、慢启动保护”三件事安排明白。记住分工——liveness 管生死、readiness 管流量、startup 管启动,并让探针只反映本进程能力,外部依赖交给重试与熔断。把这套写进你的 CI/CD 流水线 与基础镜像,新应用开箱即稳。

十二、用 kubectl 验证探针状态

配置完探针,第一件事不是等事故,而是立刻用 kubectl 确认它们真的在工作。describe 能直接看到三类探针的实时结果与最近一次探测输出,restartCount 则能反映 liveness 是否在悄悄重启你的容器。

# 查看探针配置与最近探测结果
kubectl describe pod myapp-7d8f9 -n default | grep -A6 -i "Liveness\|Readiness\|Startup"

# 看 Pod 是否被 readiness 摘流
kubectl get endpoints myapp

# 看容器重启次数(持续增长说明 liveness 在杀)
kubectl get pod myapp-7d8f9 -o jsonpath="{.status.containerStatuses[0].restartCount}"

如果 endpoints 里没有 Pod IP,说明 readiness 处于失败状态;如果 restartCount 每分钟涨一次,基本锁定是 liveness 阈值过严或端点依赖了外部服务。把这些信息接入 Uptime Kuma 自建监控,还能在探针异常时第一时间收到告警。

十三、探针与滚动更新、HPA 的联动

探针还会悄悄影响发布与扩缩容。滚动更新时,新 Pod 只有在 readiness 成功后才会被加入 Service,旧 Pod 也只在自身 readiness 失败后(或被新版本替换)才退出,这天然实现了“零中断发布”。而 HPA 基于 CPU/内存扩缩容时,如果新扩容的 Pod 因 readiness 迟迟不就绪,Service 端点数量上去了、能接流量的却没上去,就会出现“扩容了却没扛住”的假象。

场景探针的作用
滚动更新readiness 决定新旧 Pod 的流量切替时机
缩容terminating 状态先 readiness 失败再停,避免中断在途请求
HPA 扩容新 Pod readiness 就绪前不计入可用端点
节点驱逐配合 PDB 与优雅停机平滑迁移

因此,探针不是“配了就行”的装饰,而是连接部署、伸缩与稳定性的中枢。上线前务必用上面的 kubectl 命令做一次真实验证,把 restartCount、endpoints 与 readiness 状态纳入你的发布检查单。

上一篇 一致哈希实战:从原理到分布式缓存与分片落地
下一篇 Java 枚举与策略模式实战:告别冗余 if-else
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]