Kubernetes 探针(Probe)详解与生产环境配置实践
Kubernetes探针包括存活、就绪和启动三类,分别负责容器重启、流量摘除和慢启动保护。探测方式有exec、httpGet和tcpSocket,需按场景选择。配置需结合启动窗口、周期、阈值等参数,Java服务常用tcpSocket三探针并给足启动时间,Vue前端用httpGet就绪探测。典型组合包括Spring Boot、MySQL、Nginx等。常见坑有用存活代替就绪、慢启动不配启动探针、探测方式不当、参数过严、就绪依赖外部服务。监控可关注kube_pod_probe_success等指标,排障需查看Events、日志并手动复现。
``# 一、三大探针分别管什么?
K8s 的探针本质是"服务健康状态的三层校验机制",三种探针职责不同、失败后果也不同:
| 探针 | 管什么 | 失败后果 | 典型场景 |
|---|---|---|---|
livenessProbe(存活探针) | 容器是否活着 | 按restartPolicy重启容器 | 死锁、OOM、进程假死 |
readinessProbe(就绪探针) | 容器是否能用 | 从 Service Endpoints 摘除,不再收流量 | 依赖未就绪、初始化未完成 |
startupProbe(启动探针) | 慢启动保护 | 重启容器 | Java/Tomcat 启动 3 分钟以上的服务 |
一句话区分:
liveness管"生死",readiness 管"流量",startup 管"启动保护"。liveness 和 readiness 的失败后果不同——一个重启、一个摘流量,这俩别搞混。
startupProbe 比较特殊:它探测成功之前,liveness 和 readiness 都不会生效,所以它是专门给慢启动服务兜底的。
二、三种探测方式
| 方式 | 原理 | 适用场景 | 局限 |
|---|---|---|---|
exec | 容器内执行命令,退出码 0 为正常 | 复杂校验(依赖检查、文件存在性) | 依赖容器内装好命令(如 curl) |
httpGet | 请求 HTTP/HTTPS 端点,状态码 200-399 为正常 | Web 服务,能校验业务端口可用性 | 仅支持 HTTP(S) 协议 |
tcpSocket | 建 TCP 连接,连得上即正常 | 数据库、Redis 等非 HTTP 服务 | 只能判断端口存活,无法校验内部状态 |
选择原则:Web 服务优先 httpGet;端口监听类服务用 tcpSocket;需要复杂逻辑校验用 exec。
三、探针参数与黄金法则
所有探针共用同一套参数:
| 参数 | 含义 | 推荐值 |
|---|---|---|
initialDelaySeconds | 容器启动后延迟多久开始探测 | 略短于实际启动时间(如 Java 实际 40s 设 30-35s) |
periodSeconds | 探测间隔 | liveness 10-15s,readiness 5-8s |
timeoutSeconds | 单次探测超时 | httpGet/tcpSocket 1-3s,exec 2-5s |
successThreshold | 连续成功多少次算恢复 | 默认 1(readiness 滚动更新时也建议 1) |
failureThreshold | 连续失败多少次算故障 | liveness 3-5 次,readiness 2-3 次 |
terminationGracePeriodSeconds | 失败后的优雅终止时间 | 30-60s |
startupProbe 的启动窗口 = failureThreshold × periodSeconds,必须覆盖服务最慢一次的启动时间。
四、应该怎么配置
4.1 Java 服务标配:tcpSocket 三探针
测试和生产的大多数 Java 服务(如 szzx 的 qjksh、infostat、wmyc)配置完全一致,参数带注释的版本如下(测试环境写注释、生产环境没写,参数一个不差):
# argocd-apps/application/szzx/qjksh/values.yaml(测试,生产同参数)
probe:
enabled: true
startupProbe:
enabled: true
httpGet: null
tcpSocket:
port: http # 使用容器端口名称,自动引用 appConfig.port
initialDelaySeconds: 60 # 容器启动后 60s 开始检查
periodSeconds: 10 # 每 10s 检查一次
failureThreshold: 30 # 最多允许失败 30 次,总计 60s + (10s * 30) = 360s
# 存活探针:启动探针成功后接手,判断应用是否由于死锁等原因挂掉
livenessProbe:
enabled: true
tcpSocket:
port: http # 使用容器端口名称
initialDelaySeconds: 10 # 启动探针成功后,只需 10s 即可开始
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 3
# 就绪探针:启动探针成功后接手,判断应用是否可对外提供服务
readinessProbe:
enabled: true
tcpSocket:
port: http # 使用容器端口名称
initialDelaySeconds: 10 # 启动探针成功后,只需 10s 即可开始
periodSeconds: 20 # 就绪检查稍快一些,以便及时摘除故障节点
timeoutSeconds: 10
successThreshold: 1
failureThreshold: 3
这套配置的思路:
- startupProbe 给足 360 秒窗口(60s + 10s×30):东方通/Tomcat 启动慢,最坏情况要 6 分钟,保证启动期间不被误杀。
- liveness 用
tcpSocket而非httpGet:Java 服务端口起来就算活,避免业务层偶发 5xx 触发重启(这点文章里也强调了,liveness 探测条件要"轻量无副作用")。 - readiness 周期比 liveness 短(20s vs 30s):故障时能更快把实例从 Service 摘掉,滚动发布时新 pod 就绪判定也更及时。
port: http用的是容器端口名称,由模板自动引用appConfig.port,不用写死端口号,改端口不用动探针。
4.2 Vue 前端服务:httpGet 探针
前端服务(nginx 容器)用 httpGet,因为 nginx 是纯 HTTP 服务,直接请求页面最实在:
# argocd-apps/application/sccg/market-vue/values.yaml(节选)
probe:
enabled: true
readinessProbe:
enabled: true
httpGet:
path: '' # path 留空,模板自动补 SPA 首页路径
port: http
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
failureThreshold: 3
timeoutSeconds: 3
livenessProbe:
enabled: true
tcpSocket:
port: http
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3
timeoutSeconds: 3
startupProbe:
enabled: true
httpGet:
path: ''
port: http
failureThreshold: 30
periodSeconds: 10
timeoutSeconds: 3
注意这里 liveness 反而是 tcpSocket——nginx 挂不挂看端口就行,httpGet 留给 readiness 判断页面能不能访问,两边分工明确。生产环境的 gzsw-ui 等 vue 服务配置和测试完全一致。
五、组合场景与 5 个坑
文章总结的典型组合:
| 场景 | 组合 | 关键参数 |
|---|---|---|
| Spring Boot 微服务 | startup + liveness + readiness | startup 24×10s=240s;liveness initialDelay 60s;readiness period 5s |
| MySQL | liveness + readiness | liveness tcpSocket 3306;readiness exec mysqladmin ping |
| Nginx | liveness + readiness | liveness exec pgrep nginx;readiness httpGet / |
| 依赖 MQ 的服务 | readiness + liveness | readiness 校验内部健康端点(含 MQ 连接),failureThreshold 2 |
5 个坑(对应到我们环境):
1. 用 liveness 代替 readiness → 启动中的实例被塞流量,直接 5xx。我们的配置里两探针职责分明,没这个毛病。
2. 慢启动服务不配 startupProbe → 启动慢的 Java 服务被 liveness 反复重启,起不来的同时疯狂消耗资源。我们全配了,startup 窗口 360s。
3. 探测方式不当(tcpSocket 校验 Web 服务)→ 端口通但页面 500 也照样"健康"。我们 Java 用 tcpSocket 是刻意为之(liveness 轻量优先),但 readiness 其实可以更严格,后续可以评估给核心服务上 httpGet 健康端点。
4. 参数过严(如 periodSeconds=2s)→ 探测本身占资源,还可能把抖动当故障。我们的参数都按黄金法则来。
5. readiness 依赖外部不稳定服务(跨集群 DB)→ 上游一抖,实例被反复摘除,流量雪崩。这条要警惕:readiness 探针里的依赖校验别连跨集群的外部服务。
六、监控告警与排障
文章给出的探针监控指标(kube-state-metrics 提供):
| 指标 | 告警建议 |
|---|---|
kube_pod_probe_success{probe="liveness"} | 5 分钟成功率 <90% 告警 |
kube_pod_probe_success{probe="readiness"} | 5 分钟成功率 <80% 告警 |
kube_pod_probe_success{probe="startup"} | 启动后 3 分钟未成功告警 |
kube_pod_container_status_waiting_reason(ProbeFailed) | 持续 5 分钟以上告警 |
kube_pod_status_ready(0) | 持续 10 分钟以上告警 |
Grafana 可以直接导入官方 Dashboard "Kubernetes Pod Health"(ID 13105)。
排障流程(遇到探针失败时):
# 1. 看 Events,确认失败原因
kubectl describe pod <pod-name> -n <namespace>
# 关注 "Liveness probe failed: ..." / "Readiness probe failed: ..." 事件
# 2. 看日志,排查崩溃或依赖连接问题
kubectl logs --tail=100 <pod-name> -n <namespace>
# 3. 手动执行探测命令,复现问题
kubectl exec -it <pod-name> -n <namespace> -- curl -v http://127.0.0.1:8080/actuator/health
# 4. 确认是参数问题还是业务问题,再决定调整探针还是修业务
七、注意事项
probe.enabled是总开关:values.yaml 里三个探针都配了但总开关是false,一样不生效(测试 kjds base-service 就是这个状态,光看 probe 段容易误判)。httpGet.path留空:vue chart 模板会自动补 SPA 路径;其他 chart 透传,path 留空会请求/。- tcpSocket 探针的边界:端口通不代表业务健康,核心服务建议上 httpGet + 业务健康端点(如 Spring Boot Actuator),端点必须轻量、耗时 <1s。
- 探针不是越多越好:核心是"精准校验",在探测准确性和资源消耗之间取平衡。
- 测试环境探针状态和生产不一致:kjds 测试环境 13 个服务探针全关是我拉长探针参数时一起处理的,这类差异会掩盖测试环境的问题表现——测试环境没探针意味着 pod 挂了不重启、流量照常打到坏实例,排障时看不到探针事件。
评论 (0)