Kubernetes探针实战:startup/liveness/readiness配置与调优

发布时间:2026/10/21 15:08:45
Kubernetes探针实战:startup/liveness/readiness配置与调优
1. 从一次诡异 502 说起探针到底在保护什么有次凌晨一点某服务的 Pod 状态明明显示 Running但用户投诉首页一直在报 502。我登上去看容器进程活着日志也没有 panicCPU、内存都正常。诡异的是流量一打进来接口响应时间直接飙到三十秒开外然后被网关判定超时干掉。那会儿我还没把探针当回事觉得 Pod 起得来、进程不死不就完事了吗后来才反应过来问题恰恰出在进程活着和服务可用之间那条巨大的鸿沟上。Kubernetes 里的探针Probe就是来填这条鸿沟的——它由节点上的 kubelet 定期执行帮你回答三个完全不同的问题容器里的进程是不是已经完成了启动可以开始接收健康检查了容器里的进程是不是还活着需不需要被重启容器是不是已经准备好接收业务流量可以摘除或加入 Service 后端这三个问题对应 Kubernetes 内置的三类探针startupProbe启动探针、livenessProbe存活探针、readinessProbe就绪探针。它们共享同一套探测机制HTTP 请求、TCP 连接、执行命令但语义完全不同配置错了、混用了轻则 Pod 频繁重启重则流量全部打到一个还没准备好的实例上线上事故就是这样一点点攒出来的。这篇就结合我自己调过的几个真实案例把三种探针的分工逻辑、参数调优思路、常见误区和不同场景下的组合策略完整过一遍。看完你至少能回答三个问题什么情况该配哪种探针参数怎么写才算合理为什么明明配了探针服务还是炸了2. 三种探针的分工逻辑谁在管启动、谁在管存活、谁在管就绪2.1 探针是谁执行的它和容器内进程是什么关系先说一个很多人都忽略的基础事实探针不是容器里的应用自己检查自己而是节点上的 kubelet 从 Pod 的外部去戳这个容器。kubelet 是运行在每个节点上的代理进程它通过容器运行时比如 containerd来执行探针。拿 HTTP 探针举例kubelet 会直接发起一个到 Pod IP 指定端口的 HTTP 请求请求路径、端口、Host 头都由你在探针配置里指定。如果返回的 HTTP 状态码在 200 到 399 之间就认为这次探测是健康的否则就是失败。exec探针则是在容器里执行一条命令看退出码是否为 0。tcpSocket探针则是尝试建立 TCP 连接连得上就算健康。理解了这一点你就会明白一个关键推论探针的探测结果本质上是外部视角对服务可用性的判断不是你应用内部自己觉得我还行就算数。很多应用的健康检查接口用/healthz里面只查了一下进程内存根本没检查数据库连接池、下游依赖缓存这些关键资源的状态那这个探针对服务是否真的可用几乎没有任何参考价值。另外要注意探针是 kubelet 在主循环里串行执行的。如果一个节点的 Pod 很多探针本身就是一种资源开销。探测太频繁、超时设太长会把节点负载拉上去探测太稀疏故障发现又不及时。后面我会讲到这就是调参需要权衡的核心矛盾。2.2 startupProbe给慢启动应用的一条逃生通道先讲 startupProbe它是 Kubernetes 1.16 引入的也是最容易被忽略的一个。它的职责非常单一告诉 kubelet容器里的应用到底完成了启动没有。在它成功之前其他两种探针都不会执行。为什么需要这样一位保安因为很多应用启动真的慢。比如 Java 应用启动要加载 Spring 容器、连数据库、连配置中心一般得 30 秒到一两分钟有些老系统冷启动甚至要三分钟。如果你只配了 livenessProbekubelet 从容器创建那一刻起就按initialDelaySeconds倒计时时间一到就开始用存活探针去探测。应用还没起来探针一打就失败连续失败达到failureThreshold次数kubelet 就把容器杀了重启。结果就是 Pod 陷入启动-被杀-启动-被杀的 CrashLoopBackOff 死循环永远起不来。在 startupProbe 出现之前大家通常用两个办法绕过这个问题把 livenessProbe 的initialDelaySeconds调得很大比如 120 秒赌它这个时间内能起来。给 livenessProbe 配一个宽容的脚本比如脚本里去判断某个启动标志文件是否存在不存在就返回 0。这两种都很烂。第一种是盲猜时间启动慢一天就完蛋第二种是自欺欺人等于让应用自己给自己开后门探针彻底失去意义。startupProbe 的正确逻辑是启动探针失败kubelet 不会杀容器它会一直重试直到成功为止。一旦启动探针成功一次它就被标记为完成后面所有启动探测直接停止转而交给 livenessProbe 和 readinessProbe 接管。这个机制意味着你可以把启动探测的failureThreshold设得很大比如 Java 应用设个 60periodSeconds 设 5 秒那就有最多 300 秒的启动窗口基本覆盖了绝大多数慢启动场景而且完全不用担心误杀。2.3 livenessProbe判定死透了然后交给重启机制livenessProbe 解决的是这个容器要不要被重启。它的判定标准只有一条容器里的进程是否处于不可恢复的异常状态。这个状态包括但不限于死锁、内存泄漏导致 OOM 频发、goroutine 疯狂增长导致卡死、某个关键协程阻塞导致请求无响应。liveness 探测失败后kubelet 会杀掉容器然后根据restartPolicy决定是否重启它。默认的 restartPolicy 是 Always也就是说容器会被重建。这里有一个特别反直觉的点很多人理解错了livenessProbe 不是为了摘流量而是为了重启进程。它解决不了流量调度的问题一个 liveness 失败的容器在被杀之前依然还在 Service 的后端列表里依然会分到请求。所以在生产环境里你几乎不应该只依赖 livenessProbe 保护服务可用性。更关键的是livenessProbe 的判定必须足够稳不能因为业务瞬时波动就误杀容器。比如你的接口平时响应 100ms突然遇到流量尖峰响应变成 2 秒如果 liveness 探针的 timeoutSeconds 只设了 1 秒这一下就失败了。连续失败几次容器就重启了可用性不升反降。这种情况应该是还没做好准备接受流量那是 readiness 该管的事或者是启动过程中还没起来那是 startup 该管的事。拿 liveness 一刀切只会制造更多事故。2.4 readinessProbe流量调度的开关才是线上服务可用性的守护神readinessProbe 解决的是这个 Pod 能不能加入 Service 的负载均衡池能不能被分配流量。它失败后kubelet不会重启容器而是将这个 Pod 的 Ready 状态置为 False然后把它从所有 Service 的 EndpointSlice 里摘掉。注意这里说的是摘掉不是杀掉。等它恢复健康了又会被加回来。这套机制的价值在于它让进程是否存活和是否接收流量彻底解耦。容器活着但没准备好就不给流量准备好了再给流量。这跟网关里的熔断、摘除节点思路是一脉相承的。所以readinessProbe 的检查内容应该尽量贴近对外提供服务所需的所有前置条件数据库连接池是否成功初始化且有可用连接内存缓存是否加载完成依赖的下游服务比如认证中心、配置中心能不能连通消息队列消费组是否已经建立本地磁盘是否还有足够空间写日志业务说一句大白话一个请求打过来这个实例能不能在合理时间内给出正确响应。2.5 三者协作的完整时间线一个 Pod 从创建到稳定服务的全过程很多人分开理解三个探针都能懂一旦组合起来就乱了。我画个时间线你就明白了容器创建 ↓ [startupProbe 开始执行] ↓ 成功或达到阈值前成功 [livenessProbe 和 readinessProbe 开始执行] ↓ readinessProbe 成功 Pod ReadyEndpointSlice 加入Service 开始分发流量 ↓ 运行期间 readinessProbe 失败 → 摘流量容器不重启 livenessProbe 失败 → 杀容器按 restartPolicy 重启 ↓ 重启后 回到 startupProbe重新走一遍流程记住一个核心逻辑startup 是门卫负责放行其他探针readiness 是交通信号灯管流量liveness 是急救人员管生死。三者各管一段互相不替代。3. 探针配置参数的调优经验从默认值到生产可用的调整链路3.1 探针配置的五个参数逐一拆开讲不管是哪种探针Kubernetes 的配置结构是一样的。看一个典型例子livenessProbe: httpGet: path: /healthz port: 8080 initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 1 successThreshold: 1 failureThreshold: 3这五个字段的含义网上一搜一大把但我这里要用踩过坑的方式讲一遍initialDelaySeconds容器启动后等多久才开始第一次探测。这是给应用预留的启动缓冲期。但要提醒你在配置了 startupProbe 之后这个参数对 liveness 和 readiness 的意义已经弱化了——因为 startupProbe 成功之前它们根本不会执行。它更多适用于没配 startupProbe 的老配置。periodSeconds每隔多少秒探测一次。默认 10 秒生产环境我一般建议还是 10 到 15 秒。调太短比如 1 秒会让 kubelet 和应用的健康检查接口都承受不必要的压力调太长比如 60 秒故障发现速度太慢一个端口挂着但进程没死的情况要拖一分钟才被发现。timeoutSeconds单次探测的超时时间。默认 1 秒。这是最容易踩坑的参数。HTTP 探针发起请求后如果超过这个时间没有收到响应就算失败。如果健康检查接口本身涉及数据库查询或者服务在 GC 停顿期间1 秒很容易超时。我建议在服务正常响应 P99 耗时基础上再留 50% 到 100% 的余量。successThreshold连续成功多少次才认为容器恢复健康。默认 1 次一般保持默认就行。只有一种情况我会调成 2 或 3服务的健康检查接口比较毛躁偶发一次失败会短暂抖动但你不想让它抖动一下就立刻恢复流量、然后立刻又摘掉那种频繁上下线比一直不上线更伤网关。failureThreshold连续失败多少次才触发对应动作liveness 触发重启readiness 触发摘流量。默认 3 次。liveness 的场景我会建议调大到 4 到 5 次宁可多等几秒也要避免误杀。readiness 则建议保持 3 次甚至调小到 2 次因为摘流量本身不伤实例反应快点没坏处。3.2 探测方式的选型httpGet、tcpSocket、exec 各自适合什么三种探测方式应用场景差别很大。httpGet是最推荐的也是绝大多数 Web 服务的第一选择。因为它最接近真实用户的访问路径一个 HTTP 请求发过去能拿到 2xx/3xx 响应码说明从 kubelet 网络栈到容器端口、到应用进程、到 Handler 链路是通的。注意这里说的是链路通不保证业务逻辑完全健康所以健康检查接口本身的设计很重要后面我会专门讲。tcpSocket只检查端口能否建立 TCP 连接比 HTTP 探针更底层。它适合四层协议的服务比如 MySQL、Redis、gRPC如果没暴露 HTTP 健康接口的话。但它的检查粒度很粗端口能被 connect不代表服务真的能处理请求。拿它做 livenessProbe 还行做 readinessProbe 就远远不够。exec是在容器里执行命令通过退出码判定健康。它最灵活但也最危险。危险在哪因为你在容器里执行的命令本身就依赖容器环境。常见坑我举个真实的有人写了个健康检查脚本pidof java容器里却用的是基础镜像连 pidof 命令都没有探针每次执行直接报command not found退出码 127Pod 一直不 Ready。还有一个更隐蔽的坑脚本里用grep查进程列表但容器里跑的是精简镜像连 /proc 的信息都不全grep 出来的结果永远不对。我的建议是能走 HTTP 就走 HTTP走不了再说别的。如果确实需要 exec命令越简单越好而且一定要在目标镜像里手动执行一遍验证不要只在本地 Mac 上测。3.3 一套可以参考的起步配置以一个标准的 Spring Boot 服务为例假设健康检查接口GET /actuator/health分别返回 200 和 503。给出一套我常用的起步配置startupProbe: httpGet: path: /actuator/health/readiness port: 8080 periodSeconds: 5 failureThreshold: 60 timeoutSeconds: 3 readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 periodSeconds: 10 timeoutSeconds: 3 successThreshold: 1 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 periodSeconds: 15 timeoutSeconds: 3 successThreshold: 1 failureThreshold: 5几个设计思路说明一下启动探针周期 5 秒、阈值 60代表最多容忍 300 秒的启动时间给慢启动业务留足余地。正常情况下应用 30 秒就起来了启动探针一成功就退出不会有持续开销。readiness 和 liveness 用不同的健康检查接口这是一个非常关键的设计。很多团队图省事两个探针指向同一个/healthz结果一出问题就连锁反应依赖抖动导致健康检查失败readiness 摘流量同时 liveness 也开始失败容器被重启整个 Pod 重建所有连接全部断开。如果是接入层服务这就是一次小型雪崩。而拆成两个接口之后你可以让/healthz/liveness只检查进程内部最基本的标志比如一个 AtomicBoolean 是否还活着让/healthz/readiness才去检查数据库、缓存、下游依赖这些重资源。两者职责清晰fail 的边界就不会重叠。liveness 的 failureThreshold 设 5配合 15 秒的 period意味着要连续 75 秒探测失败才会重启。这个容忍度对绝大多数业务来说都够宽了也绝不会因为偶发的 GC 停顿误杀容器。4. 探针配置实战从 YAML 编写到效果验证的完整链路4.1 完整 YAML 示例一个偏实战的 Deployment配合上面的思路给一个完整的 Deployment 配置里面包含了我实际在用的探针组合apiVersion: apps/v1 kind: Deployment metadata: name: order-service namespace: production spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: containers: - name: order-service image: registry.example.com/order-service:2.4.1 ports: - containerPort: 8080 env: - name: JAVA_OPTS value: -Xms1g -Xmx1g startupProbe: httpGet: path: /healthz/startup port: 8080 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 60 readinessProbe: httpGet: path: /healthz/readiness port: 8080 periodSeconds: 10 timeoutSeconds: 3 successThreshold: 1 failureThreshold: 3 livenessProbe: httpGet: path: /healthz/liveness port: 8080 periodSeconds: 15 timeoutSeconds: 3 successThreshold: 1 failureThreshold: 5眼尖的你会发现我甚至把 startupProbe 单独拆了一个/healthz/startup接口。它和 liveness 接口的区别在于startup 接口只返回一个进程已经完成框架初始化的标记比如 Spring 容器的ApplicationReadyEvent触发后才把它置为 trueliveness 接口检查的是运行时是否还在正常工作readiness 是是否具备服务能力。三级接口逐层递进每一层的判定条件都比上一层更严格。这种设计在业务方配合的前提下能把探针的误报率降到最低。4.2 如何验证探针配置真的生效YAML 写完之后别直接往集群里一扔就觉得完事了。我有几个固定的验证步骤每次都走一遍能拦住 90% 的脑残问题。第一步用 kubectl 看状态。kubectl apply -f deployment.yaml kubectl get pods -o wide kubectl describe pod order-service-xxx如果探针配置有问题describe里 Events 尾部一般会有Unhealthy事件输出里会写明探针失败的具体原因比如Liveness probe failed: HTTP probe failed with statuscode: 500。第二步手动触发一次失败验证摘流量和重启逻辑。找一个正在 Ready 的 Pod进入容器把健康检查接口搞挂kubectl exec -it order-service-xxx -- sh # 在容器里把某个标志置为不健康比如 touch /tmp/unhealthy然后观察kubectl get pods -w kubectl get endpointslices -l kubernetes.io/service-nameorder-service如果 readiness 探针配置正确几秒钟内你会看到 Pod 变成NotReady同时对应的 EndpointSlice 里这个实例的 IP 被摘掉。kubectl get pods -w里显示的状态更有意思你会看到 Pod 还在 Running但READY列从1/1变成0/1。这就是活着但不对外服务的状态明白这个状态你就理解了探针的精髓。第三步模拟启动慢的场景。把 startupProbe 的 failureThreshold 临时调小到 3period 保持 5 秒然后重新创建 Pod。正常情况下 Pod 会一直显示Running但READY 0/1等到你恢复阈值后再看它是否正常变为 Ready。这一步骤是为了确认startup 失败不会触发重启只会让探针等待。4.3 探针配置后的持续观察维度探针不是配完就一劳永逸的。我上线新的探针配置后头一周会盯几个指标Pod 重启次数kubectl get pods里 RESTARTS 列持续增长说明 liveness 误判严重priority one 级问题。Ready 状态翻转次数如果某个 Pod 频繁在 Ready 和 NotReady 之间横跳说明 readiness 探针写得过于敏感或者这个实例本身的稳定性有问题。频繁上下线比一直下线更可怕因为它会让名叫 Service 的负载均衡器的连接池反复重建长连接请求全被打断。健康检查接口的响应时间这个往往被人忽略。如果你的健康检查接口查询了一个特别慢的数据库视图响应时间要 800ms而 timeoutSeconds 设的是 1 秒那你的 Pod 会在业务高峰时跳舞。在监控里专门给GET /healthz/readiness建一个 p99 耗时的看板能提前发现这类问题。5. 常见误区和真实踩坑复盘为什么探针都在报错但服务还是一团糟5.1 误区一liveness 和 readiness 指向同一个接口这个坑我前面已经点名了但值得展开复盘。我曾经接管过一套遗留系统里面三个服务的探针全都指向同一个/health。这个接口的逻辑是查一次数据库连一次 Redis再调一次下游的订单服务全部正常才返回 200。平时看着没啥问题直到一次下游订单服务故障接口开始返回 500。接下来的连锁反应是readiness 失败实例摘流量liveness 也失败容器被杀重启。重启后的实例刚起来又开始查数据库、连 Redis、调下游下游还是挂的于是又失败、又被杀。整个服务在十分钟内重启了十几次Kubernetes 集群的节点上全是这种重启循环的 Pod。最后拉了多少流量业务影响范围从下单接口一路扩大到所有依赖这个服务的上游。破解方案就是前面说的接口分层至少把 liveness 和 readiness 拆开。liveness 接口只查进程级信号保证它永远只在你真的需要重启容器的时候才失败。5.2 误区二exec 探针里的命令在目标容器里根本不存在有次处理一个 Nginx 服务的探针问题配置是这样的livenessProbe: exec: command: - /usr/local/bin/check-health.sh结果 Pod 全部处于 CrashLoopBackOff。我进容器一看脚本文件压根不在镜像里镜像打完包后谁都没记得把这个脚本 COPY 进去。这个案例听起来很蠢但实际发生频率不低尤其是当 Dockerfile 和 Kubernetes YAML 由不同人维护的时候。还有一个更隐蔽的版本脚本依赖的curl、jq、pgrep等命令在本地开发镜像里有但生产环境用的distroless精简镜像里没有。这种问题你要靠本地跑再多的kubectl describe也发现不了必须在目标镜像里手动执行一遍命令验证。检查清单就一句话exec 探针里的命令以及它依赖的所有二进制必须在目标镜像中真实存在且可执行。5.3 误区三timeoutSeconds 和 periodSeconds 的关系没搞懂很多人以为periodSeconds: 10的意思是每 10 秒发起一次探测。其实不完全是。当一次探测超时后下一次探测是从这次请求发出后的第 10 秒开始算还是从这次请求返回之后开始算不同的 kubelet 版本行为有差异但总体逻辑是periodSeconds 是两次探测开始时间的间隔超时只是单次探测的内部上限。举个例子如果你设了timeoutSeconds: 5、periodSeconds: 10而健康检查接口每次都耗时 4 秒那么每个 10 秒周期里有 4 秒被探测请求占用实际留给业务请求的处理时间只剩下 6 秒。如果是小应用无所谓但高流量服务会明显感觉到健康检查请求和业务请求在抢占处理线程。所以健康检查接口本身必须要轻量默认情况下单次探测耗时应该压在 100ms 以内否则就是给系统凭空增加负担。5.4 误区四所有容器都套同一套探针模板还有一次我们看到某个服务的 Pod 疯狂重启查了半天发现是它的缓存预热要将近 40 秒但配置却照搬了另一个服务的 livenessinitialDelaySeconds: 10, failureThreshold: 3, periodSeconds: 10。也就是说存活探针在容器启动后 10 秒开始探测每 10 秒一次失败 3 次就杀。40 秒的预热期内探针早在第 30 秒就把容器杀掉了于是永远在 40 秒前循环。这种问题在一个模板走天下的团队里非常普遍。探针配置必须针对每个服务的启动耗时、服务类型、依赖强弱单独设计。没有所谓的最佳配置只有适合你这个服务的配置。我一般要求团队在接口文档里明确写清楚这个服务启动需要多少秒、依赖几个外部组件、读接口 P99 是多少然后据这个信息来配置探针。5.5 误区五探针内部的健康检查逻辑本身就写得不对很多人用的健康检查接口只检查了进程自身状态完全没有检查它依赖的下游。比如应用连的数据库挂了但/healthz/readiness还是返回 200因为接口里没有查数据库。这样做的结果是数据库恢复前所有请求打到这个实例上全部超时而实例在 Service 的 EndpointSlice 里依然是 Ready 状态流量照常分发。反过来说如果 readiness 接口把下游全都检查一遍而下游偶发抖动readiness 就频繁失败实例被频繁摘流量又加回来。所以完整的思路是场景readiness 检查范围原因核心应用强依赖数据库/缓存检查数据库连接、缓存连通性但用短超时如 200ms宁可摘掉也不要让流量打到半残实例上接入网关类服务检查内存、线程池状态网关自身才是关键下游无关有本地缓存兜底的服务只要本地缓存未过期就认为 Ready下游挂了也不影响主要流量核心原则很简单readiness 探针的检查范围必须和能不能接流量强相关。跟接流量无关的依赖就不要放进 readiness 里。5.6 踩坑实例复盘一次因为探针导致的滚动发布卡死最后分享一个我印象最深的真实事故。某次发版Deployment 滚动更新卡住了新创建的 Pod 一直不 Ready旧的 Pod 也不缩容服务一直处于发布中状态用户侧偶发 5xx。排查看新 Pod 事件里面全是Readiness probe failed: HTTP probe failed with statuscode: 503。登录到新 Pod 里 curl 健康检查接口返回 503但服务本身的日志一切正常。后来发现新版本上线了一个功能健康检查接口会校验内存缓存里的一个配置项如果配置加载没完成就返回 503。而配置加载依赖一个外部的配置中心偏偏配置中心那个时段在重启。于是新版本永远认为不健康滚动更新卡死流量还压在旧版本上而旧版本没有这个逻辑服务正常。这件事给我的教训有三层健康检查接口的失败阈值要向下游抖动妥协不能把一次性外部故障放大成新实例不可用滚动发布期间新 Pod 的 readiness 失败会影响整个发布流程所以新版上线前必须确认健康检查接口不会因为短期依赖抖动而误报依赖外部组件的检查必须加超时和降级逻辑尤其是健康检查路径不能因为下游慢就把自己的探针拖垮。6. 不同业务场景的探针组合策略别再一份配置打天下了6.1 无状态 Web 服务三探针齐全readiness 最严格这是最常见的场景。我的建议是三个探针都配齐startupProbe 兜底启动时间readinessProbe 兜底依赖可用性livenessProbe 兜底进程死锁。readiness 接口检查项应该包含数据库连接池、Redis 连接、消息队列生产者状态。每个检查项要单独设超时比如单项 200ms总超时不超过 1 秒避免健康检查自身变成瓶颈。6.2 单实例且不可重启的服务慎用 liveness如果你跑的是单副本的数据库、有状态服务或者容器重启代价远大于暂时不可用的服务我强烈建议你不要配 livenessProbe或者把 failureThreshold 调到 10 以上、periodSeconds 调到 60 以上。为什么因为这类服务重启一次的成本极高主从切换、数据恢复、日志重放可能比让它暂时变成 NotReady要痛得多。liveness 的本意是自动恢复但在有状态场景下自动恢复往往带来更大的损失。我见过一个团队给单实例 Redis 配了 liveness结果一次 GC 停顿导致连续几次探测失败Redis 容器被重启缓存全部丢失在线业务直接雪崩。这种情况的正确做法是只配 readiness让流量不进这个实例人来决定何时重启。6.3 有预热/缓存加载的服务startupProbe 是你的救命稻草像 Java 应用类加载、机器学习模型加载、大数据量缓存预热这类服务启动后会有相当长一段时间不能接流量。你可以在启动逻辑里设一个标志预热完成之前/healthz/readiness返回 503预热完成后返回 200。配合 startupProbe把启动窗口拉足够长等完整启动后再让 readiness 介入。这里有个细节readiness 探针和 startupProbe 的判定是可以互补的——启动探针过关了Pod 的状态就从ContainerCreating变Runningreadiness 过关了READY列才从0/1变1/1。两者各管一段最好不要合并成一段。6.4 批处理/离线任务大部分场景根本不需要探针如果你的工作负载是一次性任务比如定时清理、离线计算它跑完就退出那探针对它没有意义。容器退出后 Kubernetes 会根据 restartPolicy 处理而不是靠 liveness 判断要不要重启。有一种例外长跑的流式处理任务比如消费消息队列的 worker这时候 livenessProbe 有价值——如果消费者线程死了但你进程还活着业务就静默停滞了。可以配一个 exec 探针检查队列消费 lag或者检查 worker 内部的存活标志让 kubelet 在消费线程死亡时重启容器。7. 最后说几句实在的探针配了三四年踩过的坑比看过的文档多我自己的体会是探针的本质不是什么高大上的技术而是运维同学和业务代码之间的一份契约。文档里写清楚了进程活着不代表服务可用你的探针就要把这句话翻译成精确的检查逻辑。如果你现在刚接触这个主题我建议不要急着一次把三种探针全部配齐。先从 readiness 开始把一个服务的接流量条件理清楚把它加到现有 Deployment 里观察几周确认它的状态翻转是合理的。然后再加 liveness而且是从非常宽松的阈值开始比如失败 10 次才重启逐步收紧到你认为安全的范围。最后再看服务启动够不够快决定要不要上 startupProbe。一步一步来每次变更都能解释清楚比一次性抄一个最佳实践模板要可靠得多。最后分享一个调试小技巧想知道当前节点上 kubelet 认为你的 Pod 健不健康不用去看控制台直接查 Pod 的.status.conditionskubectl get pod order-service-xxx -o jsonpath{.status.conditions[*].type}{.status.conditions[*].status}输出会明确告诉你ReadyTrue还是ReadyFalse、ContainersReady是真是假。配好探针之后这个命令会变成你排查服务不可用问题时的第一条命令比去看什么监控面板都快。