Kubernetes健康检查实战:探针配置、参数调优与排错指南

发布时间:2026/10/22 8:59:38
Kubernetes健康检查实战:探针配置、参数调优与排错指南 凌晨两点被报警电话吵醒某核心服务的页面一直转圈Kubernetes 集群里 Pod 状态看着是 Running但流量打过去就是没响应。这种场景做容器化的人多少都遇过十有八九就是健康检查没配好—— Pod 活着但服务其实已经“假死”了。Kubernetes 的健康检查机制Probe就是为了治这个病它让 kubelet 定期给容器“把脉”判断是继续接收流量、重启容器、还是先等等。这篇内容从探针类型、参数调优到排错实战把我踩过的坑和验证过的配置方法都写出来给正在被故障重启、流量异常困扰的运维和开发同学做个参考。1. 健康检查到底在解决什么问题1.1 没有探针的集群就像没有红绿灯的路口先还原一下没有健康检查时的行为。Pod 里的主进程只要没退出Pod 状态就是 Running。可进程活着不代表服务可用——线程池满了会拒绝请求依赖的数据库连接池耗尽会一直等待缓存热点导致请求响应从几十毫秒飙到几十秒。这些情况下进程还在但服务已经没法正常干活了。更麻烦的是 Service 的负载均衡。Kubernetes 的 Service 默认只认 EndpointEndpoint 又只认 Pod 的 IP 和端口。只要 Pod 处于 Running 状态它就会一直在 Endpoint 列表里流量照样往上打。结果就是用户请求被转发到一个“半死不活”的实例上超时重试再来一遍整个服务的可用性就被拖垮了。健康检查机制解决的就是这个信息不对称让 Kubernetes 能感知容器内部的真实状态而不是只看进程在不在。相当于给每个 Pod 装了个心跳监测仪不仅能测“有没有呼吸”还能测“干活效率怎么样”。1.2 探针机制怎么做到“精准定位”Kubernetes 提供三种探针对应三个不同的决策时机。livenessProbe 负责判断容器要不要重启readinessProbe 负责判断流量能不能打进来startupProbe 负责保护那些启动慢的容器。三个探针互相配合覆盖了容器从启动到稳定运行的完整生命周期。从实现原理上讲probe 是 kubelet 周期性执行的检查动作支持三种检测方式HTTP 请求、TCP 连接、执行命令。检测结果只有 Pass、Fail、Unknown 三种状态kubelet 根据状态决定下一步动作。这套机制的巧妙之处在于它把“健康”的定义权交给了应用自己——你说是啥就是啥你说健康端点是 /healthz那就按 /healthz 的返回码算。我见过不少团队一开始不上探针觉得“我们的服务很稳”直到线上事故教育了一轮才老老实实补上。实际上探针配置不应该是一期功能而应该是所有 Deployment 的默认标配。2. 三种探针怎么选别再搞混了2.1 livenessProbe决定容器的生死livenessProbe 的意义很简单如果检查失败kubelet 会杀掉容器然后根据 restartPolicy 决定是否重新拉起。它解决的是“容器假死”问题——进程没退出但内部逻辑已经无法响应。配置时要小心一个经典误区把业务强依赖写进 livenessProbe。假如数据库短暂不可用探测失败导致容器被杀重启重启后数据库还没恢复又失败又重启直接变成 CrashLoopBackOff。这不是在解决问题是在制造雪崩。livenessProbe 应该只检测“进程自身的存活能力”比如检查一个不依赖外部组件的内存态状态位。注意第一次配置时 initialDelaySeconds 不合理导致的误杀问题下面会细讲。2.2 readinessProbe决定流量的开关readinessProbe 失败不会杀容器而是把 Pod 从 Service 的 Endpoint 列表里摘掉停止转发流量。等恢复之后自动加回来。它管的是“能不能接客”对应上线发布、滚动更新这些场景。最典型的应用是发布场景。新版本 Pod 启动后如果 readinessProbe 还没就绪Service 不会把流量打过来。就绪之后才开始接收流量。这就避免了“进程刚起来还没完成初始化流量先来了”的尴尬。还有一个细节容易被忽略readinessProbe 失败期间Pod 虽然不接收 Service 流量但是端口仍然是通的。如果你有东西直接访问 Pod IP 和端口不受 Service 控制。这点在排查问题时要记住别被表象误导。我实际在做配置的时候readinessProbe 通常比 livenessProbe 更严格因为前端流量是用户直接感知的宁可少接点流量也不要把超时请求发给用户。2.3 startupProbe给慢启动应用留条活路有的应用启动特别慢JVM 应用加载一堆类冷启动可能就要一两分钟。如果用 livenessProbe 的 initialDelaySeconds 去迁就它意味着在启动期间容器是不可用的也没法及时发现问题因为 liveness 检查还没开始。startupProbe 就是专门来干这个的它先接管启动期的检查等容器真正启动成功之后livenessProbe 和 readinessProbe 才接手。相当于给慢启动应用设了一个“缓冲期”期间不做 liveness 判断避免启动慢被误杀。配置 startupProbe 的时候failureThreshold 和 periodSeconds 的乘积应该大于应用最大启动耗时。我一般会把 periodSeconds 设 10 秒failureThreshold 设 30这样可以容忍 300 秒的启动时间非常宽裕。2.4 到底怎么选一张表说清楚探针类型失败后果适用场景配置建议livenessProbe重启容器检测进程假死、死锁、死循环只检查进程自身状态别依赖外部组件readinessProbe摘除流量依赖就绪后才可服务、发布场景可检查依赖组件但要避免抖动频繁摘挂startupProbe重启容器启动特别慢的应用配合慢启动记录保证乘积大于启动耗时如果只有一个探针的配额我会优先选 readinessProbe。因为流量异常比容器重启更影响用户体验而且 livenessProbe 配不好还容易帮倒忙。3. 三种检测方式与关键参数调优3.1 HTTP 探针最常用的方式HTTP 探针通过请求指定路径根据 HTTP 状态码判断健康状态。200 到 399 算健康其他一律不健康。这也是用的最多的方式因为大多数 Web 服务都能轻松暴露一个健康检查端点。livenessProbe: httpGet: path: /healthz port: 8080 httpHeaders: - name: X-Health-Check value: kube-probe initialDelaySeconds: 20 periodSeconds: 15 timeoutSeconds: 3 failureThreshold: 3有几个细节值得讲一下。httpHeaders 支持自定义请求头如果你的健康端点有鉴权需求可以通过这个方式传入 Token。但注意 Token 不要写死明文在 YAML 里用 Secret 挂载的形式更稳妥。另一个坑是重定向。如果健康检查端口返回 302 或 301kubelet 的 HTTP 探针不会自动跟随重定向。所以健康端点和业务链路不要在同一个路由逻辑里健康检查的返回必须直达 200。3.2 TCP 探针简单但不够精细TCP 探针就是检查端口的连通性端口能建立连接就认为健康。适合非 HTTP 协议的服务比如 gRPC、MySQL、Redis 等。readinessProbe: tcpSocket: port: 3306 initialDelaySeconds: 10 periodSeconds: 10TCP 探针的问题在于精度低——端口能连上不代表服务正常。MySQL 如果陷入了拒绝连接以外的假死状态比如线程耗尽但还在监听端口TCP 探测仍然是通的。所以 TCP 探针更适合做兜底配合更精细的应用层探针一起用。3.3 Exec 探针最灵活也最考验想象力Exec 探针在容器内执行一条命令命令 exit code 为 0 算成功非 0 算失败。这个方式可以做很多精细的健康判断比如检查进程状态、确认某个临时文件是否存在、执行一段脚本做综合判断。livenessProbe: exec: command: - sh - -c - ps aux | grep my-server | grep -v grep periodSeconds: 20 failureThreshold: 3Exec 探针有个需要注意的地方每执行一次都会在容器里拉起一个进程如果探测频率太高会在容器里积累大量僵尸进程。尤其你是用 sh -c 执行复杂脚本的时候资源开销要比 HTTP 探针高一个量级。我建议能不用就不用实在需要的话把 periodSeconds 调大一些。3.4 参数调优initialDelaySeconds 到底怎么算其实不少事故都和 initialDelaySeconds 设置不合理直接相关。设小了容器还没起来就被杀掉陷入重启循环设大了服务已经就绪但探针迟迟不检查等于裸奔。我的做法是先用一条命令测出服务从进程启动到真正对外可用的时间然后再留 1.2 到 1.5 倍的余量。比如某服务平均启动耗时 25 秒那 initialDelaySeconds 就设 30。periodSeconds 控制检测频率。频率太高kubelet 压力大容器负载也高频率太低发现问题不够及时。一般线上我设 10 到 15 秒。timeoutSeconds 建议设 3 秒左右太短容易误判太长会让排障变慢。failureThreshold 是连续失败多少次后才触发动作默认值是 3。我在有依赖抖动的场景下会把这个值调高到 4 到 5避免因为一次网络抖动就触发容器重启或者摘流量。这里还要强调下 livenessProbe 的一个关键原则必须保证“失败一次不会立刻杀掉容器”。因为一次失败可能是网络抖动、CPU 调度延迟这类瞬时因素直接杀容器相当于把瞬时抖动放大成了服务中断。4. 实操为业务服务配置完整的健康检查4.1 前置准备服务要暴露健康端点要配置 HTTP 探针前提是应用自己得有一个对外的健康检查端点。以 Java Spring Boot 为例引入 Actuator 之后默认会提供 /actuator/health 端点。返回结构是 JSON状态字段为 UP 或 DOWN。Kubernetes 的 HTTP 探针只看 HTTP 状态码Actuator 默认情况下健康时返回 200不健康时返回 503所以可以直接用。对于非 Spring Boot 的框架无论是 Node.js 的 Express 还是 Go 的 net/http写一个健康端点就几行代码的事。关键就一点这个端点所做的检查必须能反映该服务处理业务请求的核心能力。只检查进程存活是远远不够的。4.2 一份可以直接抄的 Deployment 配置下面是一个完整配置示例服务是一个 Spring Boot 应用监听 8080 端口就绪端点有两个上下游依赖要一起检查。apiVersion: apps/v1 kind: Deployment metadata: name: demo-service labels: app: demo-service spec: replicas: 3 selector: matchLabels: app: demo-service template: metadata: labels: app: demo-service spec: containers: - name: demo-service image: registry.example.com/demo-service:v1.2.3 ports: - containerPort: 8080 name: http readinessProbe: httpGet: path: /actuator/health/readiness port: 8080 initialDelaySeconds: 15 periodSeconds: 10 timeoutSeconds: 3 failureThreshold: 3 livenessProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 30 periodSeconds: 20 timeoutSeconds: 3 failureThreshold: 3 startupProbe: httpGet: path: /actuator/health/liveness port: 8080 initialDelaySeconds: 5 periodSeconds: 10 failureThreshold: 30 resources: requests: cpu: 500m memory: 512Mi limits: cpu: 1 memory: 1Gi这个配置里我特意区分了 readiness 和 liveness 的不同健康端点。如果你用的 Spring Boot 版本较新可以配置 Actuator 暴露两组端点liveness 端点不查数据库、不查 Redis只返回进程状态readiness 端点携带完整依赖检查。这样既不会因为依赖抖动误杀容器又能及时摘除流量。我给服务配置的时候一定是“readiness 严格liveness 宽松”。readiness 挂了只是摘流量等依赖恢复还能自动加回来liveness 挂了就是重启代价大得多。4.3 参数是怎么算出来的上面的配置参数不是拍脑袋定的我把推算过程写一下。首先用测试环境观测服务在 2C4G 的资源限制下从容器启动到可以正常处理请求耗时大约 20 到 25 秒。所以 readinessProbe 的 initialDelaySeconds 取 15加上 periodSeconds 之后第一个检查点会在 15 秒这个点服务还没完全就绪失败一次没关系。failureThreshold 是 3意味着要连续 3 次失败才真正摘除流量也就是 15 10 10 35 秒时仍未就绪才会摘除。启动峰值耗时 25 秒35 秒还没就绪确实说明有问题这个阈值是合理的。livenessProbe 的 initialDelaySeconds 设 30确保服务启动完成之后才开始判定。periodSeconds 设 20正常健康检查。startupProbe 的 failureThreshold 设 30periodSeconds 设 10意味着最多允许启动耗时 300 秒。为什么留这么大余量因为有些服务首次启动时要加载 JIT 缓存、连接池预热偶发情况可能超过 60 秒。startupProbe 给了充分的缓冲而且启动期间 livenessProbe 不会执行彻底避免误杀。5. 常见问题与排查技巧实录5.1 探针误杀应用被反复重启这个问题很经典。某服务上线后一个小时重启了十几次登录控制台看 Pod 状态一直是 Running 和 CrashLoopBackOff 之间来回跳一开始没发现是探针问题。排查步骤是先看 Pod 事件找到具体触发原因。kubectl describe pod pod-name -n namespace如果事件里有Unhealthy字样再看是哪类探针失败。最常见的原因有两个initialDelaySeconds 太短应用还没起来就被 liveness 杀掉了或者 timeoutSeconds 太短健康端点在业务高峰时响应超过 1 秒探针直接判定超时失败。我用一个非常土的方法来确认应用实际启动耗时和健康检查接口响应耗时给容器设置一个相对宽松的配置观察正常情况下的检查耗时再逐渐收紧。5.2 所有 Pod 全部变成 NotReady流量全断这种场景多发生在依赖组件出问题的时候比如数据库连接池耗尽、Redis 故障。readinessProbe 检查的是完整依赖链所有副本同时失败Service 的 Endpoint 列表直接清空流量没有后端可转发。这个问题的根因不是健康检查配错了而是你把“业务可用性”和“流量调度”绑得太紧。解决思路是拆分健康检查维度readinessProbe 依然检查完整依赖但增加一层“仅存活”判断用于区分是依赖挂了还是服务本身挂了。还有一个实践技巧是给 Service 增加一个固定的“兜底后端”。这个后端不参与业务只返回一个降级提示页。这样即使业务 Pod 全部摘除用户还能看到统一的降级页面而不是直接连接失败。5.3 探针受 CPU 限流影响频繁失败某次排查发现服务不存在依赖问题但 readiness 探针总是间歇性失败。后来定位到是因为 CPU 配额设置太低服务在请求高峰期频繁触发 throttling导致健康检查接口响应变慢超过 timeoutSeconds 阈值被判失败。这个问题的本质是探针检查也会消耗 CPU、内存资源在极端情况下可能自己把自己搞死。解决思路有几个给探针接口留出足够余量比如检测逻辑用简单的文件存在性判断避免查库、查缓存等重量级操作或者调大 timeoutSeconds从 1 秒调到 3 秒再或者优化资源配额把 requests 配置得更接近实际使用量。我踩过这个坑之后的体会是资源配额和探针参数是强相关的不能分开调优。一次完整上线前我会刻意在压测环境同时压业务流量和探针频率观察是否有相互干扰。5.4 排错工具和排查思路汇总我整理了一份日常排查时最常用的命令和对应场景场景命令排查要点查看探针事件kubectl describe pod找Unhealthy、Started、Killing事件查看容器日志kubectl logs -f pod -c container对照探针失败时间点看应用日志进入容器手动检查kubectl exec -it pod -- curl localhost:8080/actuator/health模拟探针动作看实际响应查看实时资源kubectl top pod pod确认是否 CPU 限流、内存压力分析探针历史Prometheus 里的probe_success和kubelet_http_requests_duration_seconds看是否有周期性失败趋势排查思路我觉得就一句话先判断是探针误报还是服务真的不健康。手动进入容器执行一次探测能直接给出答案。如果手动探测正常但 kubelet 探测失败重点查网络策略、kubelet 到容器的访问路径。如果手动探测也失败那就是服务本身的问题抓应用日志即可。6. 健康检查和其他 Kubernetes 机制的配合6.1 和 preStop 钩子配合实现优雅停机探针决定的是“何时往后端打流量”但要实现真正的优雅下线还需要和 preStop 钩子配合。preStop 是在容器终止前执行的钩子常用来发送 SIGTERM 前先做点清理工作。lifecycle: preStop: exec: command: - sh - -c - curl -X POST http://localhost:8080/actuator/shutdown; sleep 5这个配置的含义是收到终止信号后先调用应用的 shutdown 接口让它开始优雅处理存量请求然后 sleep 5 秒等待流量排干。sleep 时间应该大于应用完成存量请求的最大耗时。我通常建议睡眠 5 到 10 秒具体根据请求平均耗时和 QPS 调整。没有配置 preStop 的滚动更新经常出现旧 Pod 已经被删掉但还有请求在处理的情况。即使 readinessProbe 已经把它摘掉了已进入队列的请求还是需要时间完成。preStop 里的 sleep 就是给这些请求争取时间。6.2 滚动更新场景下的健康检查联动滚动更新时Kubernetes 会先启动新 Pod等新 Pod 就绪后再删除旧 Pod。这里的“就绪”就是看 readinessProbe。所以如果没有 readinessProbe新 Pod 一启动就会被标记就绪然后旧 Pod 立刻被删流量随即打到一个还没准备好的新 Pod 上发布大概率翻车。配合 startupProbe 之后慢启动应用也能顺利滚动更新。新 Pod 启动期间startupProbe 一直在检查成功了之后 readinessProbe 才会开始它的就绪判定。滚动更新还有一个参数叫maxUnavailable和maxSurge控制新老副本替换比例。我一般配maxUnavailable: 0maxSurge: 1保证任何时候都有完整的副本数在服务。但这要求集群资源有足够的余量来临时多启动一个 Pod。6.3 和 HPA 的联动别让缩容杀死了不可用实例HorizontalPodAutoscalerHPA根据 CPU、内存或自定义指标调整副本数。如果某实例的 readinessProbe 已经失败意味着它不接收流量但 HPA 指标通常基于 POD 的 CPU / 内存均值。一个被摘除流量的 Pod 负载会骤降拉低了平均值可能导致 HPA 缩掉其他健康副本。这种场景下建议把 HPA 的指标改为基于就绪副本数或者自定义业务指标避免因为异常实例扭曲整体判断。简单说健康检查和 HPA 之间也需要联动调优不能各管各的。7. 关于健康检查的几条个人经验写了这么多最后总结几条我在项目里沉淀下来的经验。配置探针不是照抄文档而是要理解应用自己的启动耗时、依赖关系、流量模型。第一遵循“readiness 严格、liveness 宽松、startupProbe 保底”的原则。大多数服务最好的配置就是这三个探针都上各管一段。第二健康检查端点要尽可能简单。有能力的话单独给探针暴露一个专用端口或端点不要和业务接口混在一起避免日志污染和权限校验带来的额外开销。第三调参要有数据依据。上全链路压测环境模拟真实流量场景观察探针的成功率、耗时分布这样调出来的参数才可靠。第四探针配置好之后一定要验证“故障注入”。故意停掉某个下游依赖看探针是否正确失败容器是否按预期重启或者摘流量。没有做故障演练的探针配置就像没测试过的高可用都是摆设。健康检查这种机制看着简单实际上是把应用可用性判断的主动权从 K8s 交回给了应用自己。配置合理了集群能自动处理大部分故障配置不当反而会带来新的不稳定因素。希望这些实战经验能帮你少踩几个坑。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询