第 24 篇 k8s之健康检查:探针机制详解

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 被重启(有损)。

四、探针的黄金配置法则

探针配置不当是生产事故的常见来源。以下是几条黄金法则:

  1. 永远配置 startup probe 。如果应用启动需要 60 秒,而 liveness 的 initialDelaySeconds 只设了 30 秒,liveness 会在应用还在初始化时就判定失败并重启------然后重启后又失败,陷入 CrashLoopBackOff。startup probe 专门解决这个问题:在 startup 成功之前,liveness 和 readiness 不会执行。

  2. liveness 要比 readiness 更"宽容" 。典型配置:liveness periodSeconds=15, failureThreshold=3(45 秒窗口),readiness periodSeconds=5, failureThreshold=2(10 秒窗口)。liveness 误判的代价是重启(服务中断),必须保守;readiness 误判的代价只是暂时不接收流量,可以灵敏。

  3. 健康检查端点要轻量/health 只检查自身是否存活(可能加一个 Redis PING),不要在健康检查里执行复杂的数据库查询或外部 API 调用。慢查询会导致超时,超时触发误判重启。

  4. 避免依赖外部服务 。如果 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 思维 !

相关推荐
牛奶咖啡132 小时前
k8s容器编排技术实践——K8s对象deployment应用详解
kubernetes·deployment·deployment是什么·deployment有啥用·deployment优缺点·deployment状态解析·k8s创建资源的方式
IT策士2 小时前
第 21 篇 k8s之Pod:最小调度单元与 YAML 详解
云原生·容器·kubernetes
Benszen3 小时前
K8S存储管理
容器·rpc·kubernetes
IT策士3 小时前
第 22 篇 k8s 之 Pod: 生命周期与重启策略
云原生·容器·kubernetes
Shan12053 小时前
浅谈:无服务器WebSocket解决方案
云原生·flask·serverless
java_logo3 小时前
Docker 部署 GitLab CE 完整版教程
docker·容器·gitlab·gitlab docker部署·gitlab部署文档·gitlab部署·gitlab部署教程
maomao大哥闯天下3 小时前
高可用集群软件Keepalived
云原生
llf_cloud3 小时前
docker compose滚动部署实践
运维·docker·容器
IT策士4 小时前
第19篇 Kubernetes 架构解读:控制平面与工作节点
平面·架构·kubernetes