Kubernetes 探针实战:liveness、readiness、startup 到底怎么配线上 Pod 明明 Running,流量打进去却报 502;或者应用启动慢,还没起来就被 K8s 反复杀掉重启,陷入 CrashLoopBackOff。这两类问题十有八九是探针没配对。Kubernetes 有三种探针:liveness、readiness、startup,名字相近但职责完全不同,配错了比不配还糟。这篇讲清楚每种探针管什么、什么时候用、怎么配。三种探针,三件事livenessProbe(存活探针):检测容器是不是「卡死」了。失败 →重启容器。readinessProbe(就绪探针):检测容器是不是「能接流量」了。失败 →从 Service 端点里摘掉,不重启。startupProbe(启动探针):检测容器是不是「启动完成」了。成功之前,liveness 和 readiness 都不生效。一句话区分:liveness 决定「要不要重启」,readiness 决定「要不要给流量」,startup 决定「前两者从什么时候开始工作」。readiness:最该配、最常被忽略的那个先看一个典型事故。应用启动需要预热连接池、加载缓存,大概 20 秒。如果只配了 Service 没配 readiness:# 反例:没有 readiness,Pod 一 Running 就被塞流量spec:containers:-name:appimage:myapp:1.0ports:-containerPort:8080Pod 状态一变 Running,Service 立刻把流量转发过来,但应用还在预热,于是前 20 秒的请求全 502。加上 readiness 就解决了:readinessProbe:httpGet:path:/readyz# 应用自己判断:依赖都就绪了才返回 200port:8080initialDelaySeconds:5# 启动后先等 5 秒再开始探测periodSeconds:5# 每 5 秒探一次failureThreshold:3# 连续 3 次失败才算未就绪关键在于/readyz这个接口要真的检查依赖——数据库连得上吗、缓存加载完了吗——就绪了才回 200。这样 Pod 在没准备好之前不会进 Service 端点,流量自然不会打进来。readiness 还有个重要用途:优雅下线。滚动更新或缩容时,让/readyz先返回失败,K8s 把 Pod 从端点摘掉、不再给新流量,等存量请求处理完再真正终止,避免请求被硬切断。liveness:治「假死」,别乱配liveness 是用来救「进程还在、但已经彻底卡死(死锁、事件循环阻塞)」的容器的。失败会触发重启,所以配错代价很大。livenessProbe:httpGet:path:/healthz# 只检查进程本身活着,不要检查外部依赖!port:8080initialDelaySeconds:15periodSeconds:10failureThreshold:3timeoutSeconds:2liveness 最大的坑:探测逻辑里不要检查外部依赖。假设/healthz里去 ping 了数据库,数据库抖动 10 秒。结果是:所有 Pod 的 liveness 同时失败 → 全部被重启 → 重启后数据库还没恢复 → 继续失败 → 雪崩。数据库只是短暂抖动,你却把整个应用集群重启了个遍。所以:liveness只答「我这个进程还能响应吗」,给个最轻量的、不碰外部依赖的接口。readiness才去检查「数据库、缓存这些依赖好了吗」。依赖挂了,readiness 失败摘流量就够了,不需要重启。startup:专治启动慢的老应用有些应用(尤其是 JVM、加载大模型、跑数据库迁移的)启动要一两分钟。如果直接配 liveness,你会陷入两难:initialDelaySeconds设小了 → 应用还没起来 liveness 就失败,反复重启,CrashLoopBackOff。设大了(比如 120 秒)→ 应用真卡死时也要等两分钟才被发现,故障恢复慢。startupProbe 就是来解这个矛盾的。它成功之前,liveness/readiness 完全不跑;它一旦成功,就交棒给 liveness:startupProbe:httpGet:path:/healthzport:8080# 允许最长启动时间 failureThreshold * periodSeconds 30 * 10 300 秒failureThreshold:30periodSeconds:10livenessProbe:httpGet:path:/healthzport:8080periodSeconds:10# 启动完成后,10 秒一次的正常节奏failureThreshold:3# 连续 3 次(30 秒)卡死才重启这样:启动阶段给足 5 分钟慢慢起(startup 兜底),起来之后 liveness 用 30 秒的短周期快速发现死锁。两全其美。三种探测方式除了httpGet,探针还支持另外两种检查方式:# TCP:只看端口能不能连上,适合非 HTTP 服务(如数据库、消息队列客户端)livenessProbe:tcpSocket:port:5432periodSeconds:10# exec:在容器里执行命令,退出码 0 算成功,适合没有 HTTP 接口的场景livenessProbe:exec:command:[cat,/tmp/healthy]periodSeconds:10优先用httpGet,语义清晰、开销小;exec每次要 fork 进程,频繁探测有额外开销,慎用。参数怎么调参数含义常见坑initialDelaySeconds首次探测前等待有了 startup 就不用给 liveness 设大值periodSeconds探测间隔太密集给应用加压,太稀疏发现故障慢timeoutSeconds单次探测超时默认才 1 秒,慢接口容易误判失败failureThreshold连续几次失败才判定设 1 太敏感,抖动一下就重启successThreshold连续几次成功才恢复liveness/startup 只能是 1小结readiness:决定要不要给流量,检查外部依赖,失败只摘端点不重启;还能做优雅下线。这是最该配的。liveness:决定要不要重启,只检查进程自身、绝不碰外部依赖,否则依赖抖动会引发全体重启雪崩。startup:给慢启动应用兜底,成功前冻结 liveness/readiness;起来后交棒给短周期 liveness,兼顾「启动慢」和「快速发现死锁」。优先httpGet;failureThreshold别设 1,给抖动留余量;timeoutSeconds默认 1 秒,慢接口记得调大。一句话记忆点:liveness 管重启、readiness 管流量、startup 管开关时机;liveness 千万别查数据库。记住这条,就避开了探针最致命的那个坑。