IT策士 10余年一线大厂经验,专注 IT 思维、架构、职场进阶。我会在各个平台持续发布最新文章,助你少走弯路。
在第 22 篇中,我们学了重启策略------容器退出后怎么办。但有一个更隐蔽的问题没有解决:容器还在运行,进程没有退出,但服务已经"假死"了------比如应用陷入死锁、数据库连接池耗尽、端口还在监听但 API 已超时。重启策略对这种"活着但不可用"的状态完全无能为力。
回想第 15 篇,Compose 通过 healthcheck 解决了这个问题。K8s 的解决方案更强大:三种探针,各司其职------liveness probe(存活探针)、readiness probe(就绪探针)、startup probe(启动探针)。今天我们就来把它们彻底拆解清楚,并融入贯穿案例 Flask + Redis 应用中。
一、为什么需要三种探针?
三种探针解决的是同一个问题的三个侧面:Pod 在生命周期不同阶段的"可用性"判定。
打个比方:你开了一家餐厅(Pod),startup probe 判断"厨房是否已开火"(初始化完成),liveness probe 判断"厨师是否还活着"(进程是否正常),readiness probe 判断"是否准备好接客"(能否处理请求)。三种检查缺一不可------厨房开火了但厨师晕倒了不行,厨师活着但食材没备好也不能接客。
从技术角度看:
关键理解 :liveness 失败会重启容器 (杀伤性操作),readiness 失败只是暂时不给这个 Pod 分发流量 (无损操作)。如果把 liveness 配置得太敏感(比如 timeoutSeconds 太小),会导致正常的 Pod 被频繁重启------这是生产环境中最常见的探针配置事故。
二、三种探针的配置方式
三种探针的配置结构几乎相同,都支持以下检测方式:
2.1 检测方式
exec:在容器内执行命令,退出码 0 表示健康。
bash
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
httpGet:对容器的 IP 和指定端口发起 HTTP GET 请求,HTTP 状态码 ≥200 且 <400 表示健康。
bash
readinessProbe:
httpGet:
path: /health
port: 5000
httpHeaders:
- name: Custom-Header
value: Awesome
tcpSocket:尝试对指定端口建立 TCP 连接,连接成功即健康。适合非 HTTP 服务(如数据库、Redis、gRPC)。
bash
livenessProbe:
tcpSocket:
port: 6379
2.2 通用参数
所有探针共享相同的配置参数:
注意 :initialDelaySeconds 对于 startup probe 没有意义(startup probe 的 initialDelaySeconds 会被忽略,因为它在容器启动时就需要立即工作来探测启动进度)。对于 liveness 和 readiness,合理设置 initialDelaySeconds 可以避免应用还没启动完就被判定为失败。
三、实战:为 Flask + Redis 配置探针
现在把探针融入到我们的贯穿案例中。
3.1 部署 Redis Service(先决条件)
探针演示需要 Pod 和 Service 配合,我们先把 Redis 部署好:
bash
kubectl create deployment redis --image=redis:alpine
kubectl expose deployment redis --port=6379
kubectl get svc redis
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# redis ClusterIP 10.96.100.50 <none> 6379/TCP 10s
3.2 Pod YAML(含三种探针)
bash
apiVersion: v1
kind: Pod
metadata:
name: flask-probes-demo
labels:
app: flask-probes
spec:
containers:
- name: flask
image: flask-redis-counter:2.0
ports:
- containerPort: 5000
env:
- name: REDIS_HOST
value: redis
startupProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 12
timeoutSeconds: 3
livenessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 15
failureThreshold: 3
timeoutSeconds: 3
readinessProbe:
httpGet:
path: /health
port: 5000
periodSeconds: 5
failureThreshold: 2
timeoutSeconds: 3
3.3 探针参数解读
核心设计原则 :startup 的 failureThreshold × periodSeconds 必须大于应用的最长启动时间;liveness 的 failureThreshold × periodSeconds 应远大于 readiness 的同类乘积------liveness 是"判决死刑",必须谨慎;readiness 是"暂时休息",可以灵敏一些。
3.4 部署并验证
bash
kubectl apply -f flask-probes.yaml
kubectl get pod flask-probes-demo -w
输出:
bash
NAME READY STATUS RESTARTS AGE
flask-probes-demo 1/1 Running 0 10s
查看探针事件:
bash
kubectl describe pod flask-probes-demo | grep -A20 "Events:"
3.5 模拟故障:区分 liveness 与 readiness
测试 readiness 失败(不重启容器,只摘除流量):
bash
# 手动删除 /health 端点,模拟服务不可用
kubectl exec flask-probes-demo -- mv /app/app.py /app/app.py.bak
# 此时 /health 端点仍然存在(因为之前启动的进程还在内存中),但不会影响探针
# 更准确的测试方式:进入容器后手动模拟 Redis 不可用
kubectl exec -it flask-probes-demo -- python3 -c "
import redis
r = redis.Redis(host='invalid-host', port=6379)
try:
r.ping()
except:
print('Redis 不可达------/health 将返回错误')
"
观察 Pod 的 READY 状态变化:
bash
kubectl get pod flask-probes-demo -w
# 当 readiness 探针失败时:
# flask-probes-demo 0/1 Running 0 2m
# 注意:READY 从 1/1 变为 0/1,但 STATUS 仍然是 Running,RESTARTS 没有增加
测试 liveness 失败(重启容器):
bash
# 模拟死锁:删除 /tmp/healthy 文件(假设探针检测该文件)
kubectl exec flask-probes-demo -- sh -c "kill 1"
# 警告:这会直接杀死容器主进程
观察重启:
bash
kubectl get pod flask-probes-demo -w
# RESTARTS 列会增加
两个测试的对比清晰地说明了:readiness 失败 = Pod 还在,但不接收流量(无损);liveness 失败 = Pod 被重启(有损)。
四、探针的黄金配置法则
探针配置不当是生产事故的常见来源。以下是几条黄金法则:
-
永远配置 startup probe 。如果应用启动需要 60 秒,而 liveness 的
initialDelaySeconds只设了 30 秒,liveness 会在应用还在初始化时就判定失败并重启------然后重启后又失败,陷入 CrashLoopBackOff。startup probe 专门解决这个问题:在 startup 成功之前,liveness 和 readiness 不会执行。 -
liveness 要比 readiness 更"宽容" 。典型配置:liveness
periodSeconds=15, failureThreshold=3(45 秒窗口),readinessperiodSeconds=5, failureThreshold=2(10 秒窗口)。liveness 误判的代价是重启(服务中断),必须保守;readiness 误判的代价只是暂时不接收流量,可以灵敏。 -
健康检查端点要轻量 。
/health只检查自身是否存活(可能加一个 Redis PING),不要在健康检查里执行复杂的数据库查询或外部 API 调用。慢查询会导致超时,超时触发误判重启。 -
避免依赖外部服务 。如果 liveness 的
/health端点检查了数据库连接,而数据库本身出了问题------所有 Pod 的 liveness 都会失败、被重启,进一步加剧雪崩。liveness 只应检查自己是否"活着"(进程无死锁、端口在监听),外部依赖的可用性应放在 readiness 中检查。
五、对比 Docker Healthcheck
在第 6 篇我们学过 Docker 的 HEALTHCHECK 指令,对比一下:
Docker 的 HEALTHCHECK 是一个通用机制,K8s 探针是它的精细化升级版。K8s 社区正在推进 Container HealthCheck(KEP-4664,v1.32 alpha),可能在未来版本中支持直接从容器运行时读取 Dockerfile 中定义的 HEALTHCHECK 指令,减少重复配置,但目前仍需在 Pod YAML 中手动定义探针。
六、命令速查表
七、本篇总结
-
三种探针的定位:startup 判定"启动是否完成"(慢启动保护),liveness 判定"是否假死"(死锁恢复),readiness 判定"能否接流量"(流量控制)。
-
配置核心参数 :
periodSeconds(探测频率)、failureThreshold(连续失败次数)、timeoutSeconds(超时时间),三个参数共同决定探针的灵敏度。 -
黄金法则:startup 必需(保护慢启动),liveness 保守(避免误杀),readiness 灵敏(快速摘除故障 Pod),健康检查端点必须轻量且不依赖外部服务。
-
对比 Compose healthcheck:K8s 探针是精细化的多阶段健康检查,分别控制自愈和流量分发。
这篇是 K8s 核心中最重要的实践篇之一------探针配置直接影响生产环境的稳定性和可用性。下一篇文章------第 25 篇:Deployment 基础:声明式管理与副本控制,我们将学习如何通过 Deployment 管理 Pod 的副本数量和更新策略,开启 K8s 控制器的核心之旅。
想了解更多还可以去各个平台搜索「IT策士」,一起升级 IT 思维 !