Probe 健康检查机制
Pod Running 只说明进程已启动,不代表能正常处理请求。探针是 kubelet 判断容器是否健康的手段,决定了 kubelet 何时认为容器"可以接流量""需要重启"。配错探针,轻则流量打偏,重则引发重启风暴。
本篇目标:理解健康检查的必要性与"假死"问题,掌握 startup/readiness/liveness 三大探针的工作时机,会用 HTTP GET/TCP Socket/Exec 三种检测方式,并能调优探针参数。
1. 容器健康检查的必要性与假死处理
1.1 为什么不能只看进程
容器进程活着(Running)并不等于服务可用:
- 应用启动了但依赖(数据库、缓存)没连上;
- 应用死锁、goroutine 卡死但进程不退出(假死);
- 启动慢的应用在初始化完成前收到流量会报错。
没有探针时,kubelet 只保证"进程在跑",无法区分"活着但坏了"。
1.2 假死的两种后果
| 问题 | 后果 |
|---|---|
| 假死的容器一直留在 Service 后端 | 请求打到坏 Pod,故障面扩大 |
| 假死的容器不重启 | 永远无法自愈 |
探针解决这两个问题:readiness 把坏 Pod 从 Service 摘除,liveness 重启确认没救的容器。
2. 三大探针类型与工作时机
2.1 三种探针的分工
| 探针 | 作用 | 失败后果 | 典型使用 |
|---|---|---|---|
| startup | 判断容器是否已启动完成 | 阻塞 readiness 和 liveness,直到首次成功 | 启动慢的应用(Java、数据库) |
| readiness | 判断容器是否可以接流量 | 从 Service 后端移除,不重启容器 | 所有接收请求的服务 |
| liveness | 判断容器是否还"活着" | 重启容器 | 死锁、无响应的场景 |
2.2 工作时机
容器启动
→ startupProbe 成功前:readiness/liveness 不启动
→ startupProbe 成功后:readiness 决定是否接流量,liveness 决定是否重启
3. 探针的三种检测方式
3.1 检测方式对比
| 方式 | 验证什么 | 适用 |
|---|---|---|
httpGet | HTTP 端点返回 2xx/3xx | Web/API 服务(最常用) |
tcpSocket | 端口能否建立 TCP 连接 | 纯监听端口的组件(MySQL、Redis) |
exec | 容器内命令退出码为 0 | 无法用网络探测的场景 |
3.2 配置示例
containers:
- name: api
image: registry.example.com/api:1.4.2
ports:
- containerPort: 8080
# 启动探针:给 Java 应用足够启动时间
startupProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 0
periodSeconds: 5
failureThreshold: 30 # 最多等 30×5=150 秒启动
# 就绪探针:决定是否接入 Service 后端
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 10
failureThreshold: 3 # 连续失败 3 次才标记 NotReady
successThreshold: 1
# 存活探针:仅在确认需要重启时配置
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 30
failureThreshold: 5 # 连续失败 5 次(150 秒)才重启
3.3 三种方式的写法
# HTTP GET
readinessProbe:
httpGet:
path: /ready
port: 8080
httpHeaders:
- name: X-Health-Check
value: "1"
# TCP Socket
readinessProbe:
tcpSocket:
port: 3306
periodSeconds: 10
# Exec
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
4. 探针关键参数调优
4.1 参数速查
| 参数 | 含义 | 建议 |
|---|---|---|
initialDelaySeconds | 容器启动后等多久开始探测 | startup probe 设为 0,其他按需 |
periodSeconds | 探测间隔 | readiness 5-10s,liveness 20-30s |
timeoutSeconds | 单次探测超时 | 通常 1-3s |
failureThreshold | 连续失败多少次判定为失败 | readiness 2-3,liveness 3-5 |
successThreshold | 连续成功多少次判定为成功 | readiness 1-2 |
4.2 选择矩阵
| 场景 | 建议配置 | 原因 |
|---|---|---|
| 接收流量的无状态服务 | readiness 必须,启动慢时加 startup | 未就绪的 Pod 必须从 Service 后端摘除 |
| 启动慢:JVM 预热、加载模型 | startup | 延长就绪窗口,避免启动期被 liveness 误杀 |
| 死锁 / 内存泄漏需要自愈 | liveness(确认后加) | "重启是唯一恢复手段"时才配置 |
| Job / CronJob | 不配置探针 | 成败看退出码,与 Service 流量无关 |
| 数据库等有状态副本 | readiness + startup,liveness 谨慎 | liveness 误杀可能打断主从同步 |
4.3 常见坑
- readiness 缺失:Pod 一
Running就被加入 Service 后端,故障面瞬间扩大; - liveness 误杀:慢查询、GC 停顿、CPU 节流导致的瞬时超时被误判为"卡死",容器被反复重启;
- 探针端点混用:
/healthz永远返回 200、不检查任何依赖,数据库断了探针照样成功。应分离两个端点:liveness 用进程存活检查,readiness 检查 DB、缓存等关键依赖; - startup 与初始延迟叠加:既配了 startup,又给 readiness 加
initialDelaySeconds,两段时间相加,Pod 迟迟不就绪; - 资源 limit 过小拖累探针:CPU limit 太小 → 请求被节流 → 探针超时 → liveness 重启 → 重启后又节流,陷入恶性循环。
5. 练习
练习 A
- 为一个 Deployment 添加
readinessProbe(httpGet),用kubectl describe pod确认探针生效 - 故意让就绪探针端点返回 500,观察 Pod 从 Service EndpointSlice 中移除
- 修复端点后观察 Pod 重新加入后端
练习 B
- 给一个启动需要 20 秒的应用配置
startupProbe(periodSeconds: 5、failureThreshold: 10),观察 startup 期间 readiness 是否被阻塞 - 配置
livenessProbe且failureThreshold: 1,观察一次探测失败即触发重启,理解误杀风险 - 对比
httpGet与tcpSocket探测一个不存在的路径/端口,理解两种方式的差异
下一篇:HPA 自动扩缩容。