【最详细】Kubernetes探针介绍、应用与最佳实践

文章目录

  • 概述
  • 一、探针种类、方法与使用场景
    • [1. 探针种类(Probe Types)](#1. 探针种类(Probe Types))
    • [2. 探针检测方法(Handler Types)](#2. 探针检测方法(Handler Types))
    • [3. 探针关键参数](#3. 探针关键参数)
  • 二、探针使用案例
    • [1. livenessProbe(存活探针)](#1. livenessProbe(存活探针))
    • [2. readinessProbe(就绪探针)](#2. readinessProbe(就绪探针))
    • [3. startupProbe(启动探针)](#3. startupProbe(启动探针))
  • 三、探针接口设计最佳实践
    • [1. 探针目标与接口职责对照表](#1. 探针目标与接口职责对照表)
    • [2. 每种探针对应接口的设计最佳实践](#2. 每种探针对应接口的设计最佳实践)
      • [Liveness Probe 接口(/live 或 /health/live)](#Liveness Probe 接口(/live 或 /health/live))
      • [Readiness Probe 接口(/ready 或 /health/ready)](#Readiness Probe 接口(/ready 或 /health/ready))
      • [Startup Probe 接口(/startup 或 /started)](#Startup Probe 接口(/startup 或 /started))
      • [反面案例 vs 正确做法](#反面案例 vs 正确做法)

概述

Kubernetes(简称 k8s)中的探针(Probes)是用于检测容器健康状态的重要机制,它帮助 Kubernetes 决定何时将 Pod 加入服务流量、何时重启容器,以及何时从服务中剔除不可用的实例。

一、探针种类、方法与使用场景

1. 探针种类(Probe Types)

Kubernetes 提供了三种类型的探针:

(1) livenessProbe(存活探针)

  • 作用:判断容器是否仍在运行。
  • 行为:如果探针失败,kubelet 会杀死容器,并根据重启策略(restartPolicy)决定是否重启。
  • 典型场景:应用陷入死锁、内存泄漏、无限循环等无法自行恢复的状态。

(2) readinessProbe(就绪探针)

  • 作用:判断容器是否准备好接收流量。
  • 行为:如果探针失败,Pod 的 IP 地址会从所有 Service 的 Endpoints中移除,即不再接收新请求。
  • 典型场景:应用启动较慢(如加载大模型、连接数据库)、依赖外部服务未就绪等、应用短暂不可用时避免影响流量。

(3) startupProbe(启动探针,v1.16+ 引入)

  • 作用:判断容器是否已成功启动。
  • 行为:在 startupProbe 成功之前,liveness 和 readiness 探针不会执行。
  • 典型场景:启动时间很长的应用(如 Java 应用、大型 ML 模型加载),避免因启动慢被误杀。

⚠️ 注意:三种探针可以同时配置,但 startupProbe 优先级最高,在其成功前其他探针不生效。

2. 探针检测方法(Handler Types)

每种探针都支持以下三种检测方式:

方法 说明
exec 在容器内执行一个命令,退出码为 0 表示成功。
httpGet 向容器发送 HTTP GET 请求,响应状态码在 200--399 之间表示成功。
tcpSocket 尝试与容器指定端口建立 TCP 连接,能连通即成功。

3. 探针关键参数

yaml 复制代码
initialDelaySeconds: 5     # 容器启动后等待多少秒才开始探测
periodSeconds: 10          # 探测间隔(秒)
timeoutSeconds: 5          # 探测超时时间
successThreshold: 1        # 连续成功多少次才算通过(liveness 必须为1)
failureThreshold: 3        # 连续失败多少次才算失败
  • 对于 livenessProbe,successThreshold 必须为 1。
  • 对于 readinessProbe,可设为>1,用于容忍短暂失败。

二、探针使用案例

1. livenessProbe(存活探针)

yaml 复制代码
livenessProbe:
  httpGet:
    path: /live
    port: 8080
  initialDelaySeconds: 15   # 容器启动后等待多少秒才开始探测
  periodSeconds: 20         # 探测间隔(秒)
  timeoutSeconds: 5         # 单次探测超时时间
  failureThreshold: 3       # 连续失败多少次才判定为"不存活"
  successThreshold: 1       # 成功阈值(liveness 必须为 1)

参数详解:

参数 默认值 说明
initialDelaySeconds 0 容器启动后延迟多久开始第一次探测。对慢启动应用至关重要(但更推荐用 startupProbe 来兜底)。
periodSeconds 10 每隔多少秒执行一次探测。建议 10~30 秒,太频繁影响性能,太稀疏恢复慢。
timeoutSeconds 1 单次探测允许的最大耗时,超时即视为失败。建议 2~5 秒。
failureThreshold 3 连续失败多少次才触发容器重启。总容忍时间为:(timeoutSeconds + periodSeconds) × (failureThreshold - 1) + timeoutSeconds,简化估算:≈ periodSeconds × failureThreshold
successThreshold 1 livenessProbe 必须为 1,即一次成功就算恢复(不能设为 >1)。

⚠️ 注意:

  • liveness 接口必须轻量、只读、无外部依赖
  • 避免在 liveness 中检查数据库、Redis、下游服务
  • 合理设置failureThreshold:太小,网络抖动导致误杀;太大,故障恢复慢。
  • 配合日志和监控

🔹 只关心"我还能不能活",不关心"我能不能干活"。

🔹 失败 = 重启,所以必须谨慎设计失败条件。

🔹 它是最后的安全网,不是日常健康检查。

2. readinessProbe(就绪探针)

yaml 复制代码
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5    # 容器启动后延迟多少秒开始探测
  periodSeconds: 10         # 探测间隔(秒)
  timeoutSeconds: 3         # 单次探测超时时间
  failureThreshold: 3       # 连续失败多少次才判定为"未就绪"
  successThreshold: 1       # 连续成功多少次才算"就绪"(可 >1)

参数详解:

参数 默认值 说明
initialDelaySeconds 0 启动后等待多久开始探测。对慢启动应用很重要(但更推荐配合 startupProbe)。
periodSeconds 10 每隔多少秒探测一次。建议 5~15 秒。
timeoutSeconds 1 单次探测最大耗时,超时即失败。建议 2~5 秒。
failureThreshold 3 连续失败多少次才将 Pod 标记为 NotReady。
successThreshold 1 可设为 >1(如 2),用于防止因短暂抖动导致频繁切换 Ready 状态。

场景 :数据库暂时不可用 → Pod 不接收流量

时间 事件
T=0s Pod 启动
T=5s /ready 探测 → DB 连接失败 → 503 ❌(第1次失败)
T=15s 第二次失败 ❌
T=25s 第三次失败 ❌ → 达到 failureThreshold=3
T=25s+ Pod 状态为 Running but NotReady
T=30s Service Endpoints 不包含该 Pod → 零流量打入 ✅
T=60s DB 恢复
T=65s /ready 首次成功 ✅(第1次)
T=75s 第二次成功 ✅ → Pod 变为 Ready
T=76s 流量自动恢复 ✅

⚠️ 注意:

  • 检查所有关键外部依赖:DB、Redis、Config Server、认证服务等。
  • 使用短连接或连接池 ping:避免长期占用连接。
  • 设置合理的 successThreshold(如 2):防止因网络抖动频繁进出 Ready 状态。
  • 配合 preStop hook 实现优雅下线:
yaml 复制代码
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 10"]  # 先 sleep,同时让 readiness 失败
  • 监控 NotReady Pod 数量:通过 Prometheus 报警。

🔹 "能跑 ≠ 能干" ------ Running 不等于 Ready。

🔹 流量开关由 readiness 控制,不是由容器是否启动决定。

🔹 它是服务网格、滚动更新、弹性伸缩的基石。

3. startupProbe(启动探针)

yaml 复制代码
startupProbe:
  httpGet:
    path: /startup
    port: 8080
  initialDelaySeconds: 0     # 容器启动后多久开始第一次探测(秒)
  periodSeconds: 5           # 探测间隔(秒)
  timeoutSeconds: 2          # 单次探测超时时间(秒)
  failureThreshold: 10       # 允许连续失败的最大次数

参数详解:

参数 默认值 说明
initialDelaySeconds 0 容器启动后等待多少秒才开始第一次探测。对于启动极慢的应用可设为 5~10 秒。
periodSeconds 10 每隔多少秒探测一次。建议设为 3~10 秒。
timeoutSeconds 1 单次探测允许的最大耗时,超时即视为失败。
failureThreshold 3 最关键参数! 表示最多允许连续失败多少次。总容忍时间为:(initialDelaySeconds) + (periodSeconds × failureThreshold)
  • 只要在这 60 秒内有一次探测成功,startupProbe 就算通过,之后 livenessProbe 和 readinessProbe才会开始工作。

  • 如果 startupProbe 在其最大容忍时间(即 initialDelaySeconds + periodSeconds × failureThreshold)后仍然探测失败,Kubernetes 会认为容器"启动失败",并按照 Pod 的重启策略(restartPolicy)进行处理------通常是杀死容器并重新创建(重启)
    ⚠️ 注意:

  • startup 接口必须轻量:只检查"是否初始化完成",不要连数据库。

  • 合理设置容忍时间(留足余量),宁可多给,不要少给

  • 所有启动时间 > 30 秒的应用都应配置 startupProbe。

  • 不要在 startupProbe 中做 readiness 的事(如检查 DB),那是 readinessProbe 的职责。

  • 监控 startupProbe 失败事件:可通过 Prometheus 抓取kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} 或事件日志。

🔹 startupProbe 成功前,liveness 和 readiness 不生效。

🔹 startup 接口只关心"我启好了没",不关心"我能干活吗"。

🔹 宁可多给几秒,也不要让 Pod 死在黎明前。

三、探针接口设计最佳实践

下面从 三种探针的特性出发,系统性地阐述 健康检查接口的最佳实践设计方法。

1. 探针目标与接口职责对照表

探针类型 核心目标 健康检查接口应验证的内容 不应包含的内容
startupProbe 判断容器是否已完成启动 应用主进程已启动、初始化逻辑(如加载模型、配置)完成 外部依赖(DB、缓存)连通性
readinessProbe 判断是否可以接收流量 所有外部依赖就绪(DB、Redis、API 网关等) 应用内部状态(如内存泄漏、死锁)
livenessProbe 判断是否需要重启容器 应用是否处于可恢复的运行状态(无死锁、未崩溃) 外部依赖失败(不应因 DB 挂了重启)

2. 每种探针对应接口的设计最佳实践

Liveness Probe 接口(/live 或 /health/live)

✅ 应该做:

  • 仅检查应用自身是否处于可运行状态:主线程未阻塞、内存未 OOM、无死锁

  • 最好是一个纯内存操作,不涉及 I/O。

  • 即使外部依赖(如 DB)宕机,只要应用本身还能运行(比如有重试队列),就应返回成功。

  • Liveness 只对不可恢复错误返回失败(如死锁)。
    ❌ 不应该做:

  • 连接数据库、调用外部 API。

  • 因外部服务不可用而返回失败(这会导致不必要的重启)。

示例(最简形式):

python 复制代码
# 检查内部状态标志(如后台线程是否存活):
if not background_worker.is_alive():
    return jsonify({"error": "worker dead"}), 500

⚠️ 极简即可!甚至可以直接返回 200,因为如果进程挂了,根本不会响应。

Readiness Probe 接口(/ready 或 /health/ready)

✅ 应该做:

  • 验证所有关键外部依赖是否可用:数据库连接池是否能获取连接、Redis 是否可 ping、下游微服务是否可达(谨慎使用)

  • 返回 200 仅当所有依赖就绪,可安全接收流量。

  • Readiness 对暂时不可用返回失败(如 DB 连接池满)。

  • /ready 返回 200 但 body 是 {"ok": false},K8s 仍认为就绪(只看状态码)
    ❌ 不应该做:

  • 检查非关键依赖(如日志服务、监控上报)。

  • 执行写操作或修改状态。

  • 因单点依赖失败导致整个应用不可用(可考虑降级逻辑)。

示例(最简形式):

python 复制代码
@app.route('/ready')
def readiness_check():
    try:
        # 检查数据库
        db.session.execute(text("SELECT 1"))
        # 检查 Redis
        redis_client.ping()
        return jsonify({"status": "ready"}), 200
    except Exception as e:
        app.logger.warning(f"Readiness check failed: {e}")
        return jsonify({"error": "dependencies not ready"}), 503

⚠️ 注意:避免在 readiness 中做"全链路健康检查",否则容易引发级联故障。

Startup Probe 接口(/startup 或 /started)

✅ 应该做:

  • 检查应用主进程是否已完全初始化(例如:模型加载完毕、配置解析完成)。

  • 返回成功仅当内部初始化逻辑完成。

  • 轻量、快速、无外部依赖。
    ❌ 不应该做:

  • 连接数据库、调用外部服务。

  • 执行耗时操作(如全表扫描)。

示例(最简形式):

python 复制代码
@app.route('/startup')
def startup_check():
    if app.config.get('INIT_DONE'):
        return jsonify({"status": "started"}), 200
    else:
        return jsonify({"error": "still initializing"}), 503

💡 提示:可在 init 或 before_first_request 中设置 INIT_DONE = True。

反面案例 vs 正确做法

场景 错误做法 正确做法
数据库挂了 liveness 返回 500 → 容器被反复重启 liveness 仍返回 200;readiness 返回 503 → 流量切断,但容器保留
应用启动慢(30s) 无 startupProbe,liveness 在 10s 超时杀死容器 配置 startupProbe,允许最多 60s 启动
缓存不可用 readiness 检查缓存失败 → 整个服务不可用 若缓存非关键,readiness 忽略;或实现降级逻辑
相关推荐
Risk Actuary2 小时前
磁道优化分布的一道题
linux·运维·服务器
一周困⁸天.2 小时前
K8S-特殊容器
云原生·容器·kubernetes
亚控科技2 小时前
亚控KingWater+DeepSeek让湖南常德水厂“智”变升级
运维·智慧水务·kingscada·亚控科技
weixin_462446232 小时前
【实践操作】linux记录terminal终端日志 录屏
linux·运维·服务器
飞Link3 小时前
Docker基础知识
运维·docker·容器
水天需0103 小时前
Linux 命令行换行完全指南
linux·运维·服务器
秋刀鱼 ..3 小时前
第五届机电一体化、自动化与智能控制国际学术会议(MAIC 2025)
运维·人工智能·python·机器人·自动化·制造·新人首发
回忆是昨天里的海3 小时前
docker存储-卷映射
运维·服务器·docker
凯子坚持 c3 小时前
Docker常见问题(多种类似命令之间的区别)
运维·docker·容器