深色模式
liveness/readiness/startup 探针配置
摘要:探针配错比不配更危险。本文讲清三种探针各自的触发后果与使用场景,给出 HTTP/TCP/命令三种检查方式的配置示例,以及超时参数如何避免「启动慢被反复杀」的陷阱。
适用环境
- 可用 K8s 集群 +
kubectl - 应用需提供一个健康检查接口(如
/healthz) - 示例镜像:
nginx:alpine
操作步骤
一、三种探针的区别
| 探针 | 失败后果 | 用途 |
|---|---|---|
livenessProbe | 重启容器 | 检测死锁等自愈不了的状态 |
readinessProbe | 摘出 Service Endpoints(不接流量) | 检测能否处理请求 |
startupProbe | 失败则杀容器;成功后 liveness 才接管 | 保护慢启动应用 |
危险
livenessProbe 用重依赖(如查数据库)是大忌:数据库抖动会导致所有 Pod 同时重启,小故障被放大成全局雪崩。liveness 只应检查进程自身是否存活。
二、三种检查方式
yaml
spec:
containers:
- name: app
image: nginx:alpine
ports:
- containerPort: 80
# 1. HTTP 检查(最常用)
livenessProbe:
httpGet:
path: /healthz
port: 80
httpHeaders:
- name: X-Probe
value: kubelet
initialDelaySeconds: 15
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
# 2. readiness,判定标准可以比 liveness 严格
readinessProbe:
httpGet:
path: /ready
port: 80
periodSeconds: 5
failureThreshold: 2
# 3. TCP 端口检查
# readinessProbe:
# tcpSocket:
# port: 80
# periodSeconds: 10
# 4. 容器内执行命令,返回码 0 视为健康
# livenessProbe:
# exec:
# command: ["sh", "-c", "test -f /tmp/healthy"]
# periodSeconds: 51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
三、慢启动应用必须配 startupProbe
Java、大模型服务启动可能要几分钟,若只靠 liveness 的 initialDelaySeconds 兜,要么等太久(故障发现慢),要么被误杀。
yaml
startupProbe:
httpGet:
path: /healthz
port: 80
periodSeconds: 5
failureThreshold: 60 # 60 × 5s = 最多给 5 分钟启动时间
livenessProbe:
httpGet:
path: /healthz
port: 80
periodSeconds: 10
failureThreshold: 31
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
startupProbe 成功前,liveness 和 readiness 都不会执行。
四、关键参数换算
- 容器启动后首次探测延迟 =
initialDelaySeconds - 判定失败的连续次数 =
failureThreshold - 最长容忍启动时间 ≈
initialDelaySeconds + failureThreshold × periodSeconds
注意
timeoutSeconds 默认只有 1 秒。健康检查接口若依赖外部调用很容易超时,导致探针一直失败。建议设为 3-5 秒,并保证 /healthz 只做内存级检查。
五、探针与滚动更新的关系
maxUnavailable: 0 + readinessProbe 才能做到零中断发布:
- 新 Pod 起来但 readiness 未过 → 不进 Endpoints → 不接流量;
- readiness 通过 → 进 Endpoints → 开始接流量;
- 旧 Pod 才被删除。
如果只配 liveness 不配 readiness,新 Pod 一起动就被认为可用,此时服务还没初始化完,请求会失败。
六、查看探针状态
bash
kubectl describe pod <pod> | grep -A10 "Liveness\|Readiness"
kubectl get pod <pod> -o jsonpath='{.status.conditions}' | tr ',' '\n'
kubectl get ep <service> # 未就绪的 Pod 不会出现在这里1
2
3
2
3
应用日志里也会看到探针请求(kubelet 默认带 kube-probe 的 User-Agent)。
七、临时摘流排查
想让某个 Pod 暂时不接流量又不想删它:
最快速的办法是摘掉 Service selector 所匹配的标签(- 结尾表示删除标签),该 Pod 会立刻从 Endpoints 中消失:
bash
kubectl label pod <pod> app- # 删除 app 标签,Pod 不再被 Service 选中
kubectl get ep <svc> # 确认该 Pod IP 已移除
kubectl label pod <pod> app=web # 加回来即可恢复接流1
2
3
2
3
更规范的做法是让 /ready 接口读一个可动态开关的配置项。
验证
- [ ] 故意让
/healthz返回 500,观察 Pod 是否重启(liveness) - [ ] readiness 失败时,
kubectl get ep <svc>中该 Pod IP 消失 - [ ] 慢启动应用加了 startupProbe 后不再被反复杀
- [ ]
kubectl describe pod没有探针失败的 Events
常见坑
- 服务一启动就被杀:
initialDelaySeconds太短或没配 startupProbe。 - 滚动更新期间 502:只配了 liveness 没配 readiness,或 readiness 检查太宽松(只查端口不查依赖)。
- 探针把服务压垮:
periodSeconds设成 1 秒且接口很重,kubelet 请求叠加打满应用。 - liveness 查数据库导致雪崩:见上文危险提示,liveness 必须只查自身。
- 容器端口写错:
httpGet.port要用容器实际监听的端口,可用 name 引用ports[].name。