深入理解 Kubernetes 中的探针

文章目录

深入理解 Kubernetes 中的探针

在 Kubernetes 中,容器化应用的健康状态对整个系统的稳定性至关重要。为了确保应用始终处于可用、响应和就绪的状态,Kubernetes 提供了三种类型的探针(Probes)Liveness Probe(存活探针)Readiness Probe(就绪探针)Startup Probe(启动探针)。这些探针帮助 Kubernetes 自动判断容器是否健康、是否准备好接收流量,以及是否已经成功启动。


为什么需要探针?

在传统的单机部署中,我们通常通过进程是否存在来判断服务是否运行。但在分布式系统和微服务架构中,一个进程可能仍在运行,但其内部逻辑已经"卡死"或无法正常处理请求(例如数据库连接断开、死锁、无限循环等)。此时,仅靠进程状态无法准确反映服务的真实健康状况。

Kubernetes 的探针机制允许你自定义健康检查逻辑,让平台能够:

  • 自动重启"假死"的容器(Liveness)
  • 避免将流量转发给尚未准备好的 Pod(Readiness)
  • 给慢启动应用足够的时间完成初始化(Startup)

这大大提升了系统的自愈能力服务可靠性

探针的作用 可以 根据情况 来完成 自动重启 以及 流量转发到 ready的pod 上面。


1. Liveness Probe(存活探针)

作用

Liveness Probe 用于判断容器是否"还活着"。如果探针失败,Kubernetes 会认为该容器已进入不可恢复的错误状态,自动重启该容器

存活探针 探测失败 则会重启容器

使用场景
  • 应用出现死锁、内存泄漏导致无响应
  • 内部状态异常但进程未退出
  • 需要自动恢复机制而无需人工干预

spec.containers[0].livenessProbe

yaml 复制代码
livenessProbe:
  failureThreshold: 2   # 连续失败 2 次才认为不健康(触发重启)
  httpGet:
    path: /health/
    port: 8090  # 容器启动端口
    scheme: HTTP
  initialDelaySeconds: 30  # 容器启动后,等待 30 秒才开始第一次探测
  periodSeconds: 30   	# 之后每 30 秒探测一次
  successThreshold: 1  #  只要 1 次成功就认为健康(对 liveness 来说通常固定为 1)
  timeoutSeconds: 1   # 每次 HTTP 请求最多等 1 秒,超时算失败
存活探针里面需要写什么?

livenessProbe 只回答一个问题:这个进程还活着吗?

不应该 因为外部依赖(DB、Redis、API 等)失败而返回失败。

错误的做法 在存活探针中检查数据库连接, 检查外部API 等

python 复制代码
# ❌ 错误做法
def healthz(request):
    db_ok = check_database()  # ← 查数据库
    if not db_ok:
        return JsonResponse({"status": "dead"}, status=500)
    return JsonResponse({"status": "alive"})

这样的问题 会出现 雪崩式重启

  1. 数据库短暂不可用(网络抖动、主从切换)
  2. 所有 Pod 的 livenessProbe 失败
  3. Kubernetes 重启所有容器
  4. 容器重启后又连不上 DB → 再次失败 → 再次重启
  5. 整个服务彻底不可用,即使 DB 已恢复!

⚠️ 注意:不要在 Liveness 探针中加入过于严格的依赖(如数据库连接),否则可能导致频繁重启("重启风暴")。


2. Readiness Probe(就绪探针)

作用

Readiness Probe 用于判断容器是否准备好接收流量 。如果探针失败,Pod 会被从 Service 的 Endpoints 中移除,不再接收新请求,但容器不会被重启。

使用场景
  • 应用启动后需要加载大量缓存或配置
  • 依赖的外部服务(如数据库、API)暂时不可用
  • 执行耗时的初始化任务
示例配置
yaml 复制代码
readinessProbe:
  failureThreshold: 2
  httpGet:
    path: /ready/
    port: 8090
    scheme: HTTP
  initialDelaySeconds: 5
  periodSeconds: 10
  successThreshold: 1
  timeoutSeconds: 1

只有当 http://pod_id:8090 ,返回200,才认为 Pod 就绪。否则,即使容器在运行,也不会被加入到负载均衡中。
✅ 优势:实现优雅上线/下线,避免请求打到未准备好的实例上。


Ready 探针中一般要检查 所有重要依赖和状态,比如redis, mysql 是否可以正常连接,外部依赖是否连通

3. Startup Probe(启动探针)

作用

Startup Probe 是为启动缓慢的应用 设计的。在 Startup Probe 成功之前,Liveness 和 Readiness 探针不会执行。一旦 Startup Probe 成功,其他两个探针才开始工作。

使用场景
  • Java 应用(如 Spring Boot)冷启动时间长
  • 机器学习模型加载耗时
  • 需要预热或初始化大量资源的服务
示例配置
yaml 复制代码
startupProbe:
  failureThreshold: 20
  httpGet:
    path: /startup/
    port: 8090
    scheme: HTTP
  initialDelaySeconds: 5
  periodSeconds: 5
  successThreshold: 1
  timeoutSeconds: 2

最多等待 5 × 20 + 5 = 105 秒(5 分钟)让应用启动。在此期间,Liveness/Readiness 不会干扰启动过程。
💡 这是 Kubernetes 1.18+ 引入的重要特性,解决了"慢启动应用被误杀"的经典问题。

最大启动容忍时间 为:initialDelaySeconds + periodSeconds × failureThreshold

5 × 20 + 5 = 105

Kubernetes 会在 前 105 秒内(含)最多尝试 20 次探测.

如果在这20次内有一次成功(successThreshold: 1),就认为启动成功,后续由 liveness/readiness 接管, 此后不再进行探测。

如果20次都失败,则在第 105 秒左右(具体略小于或等于 105 秒)判定启动失败,Pod 被重启。


三者协同工作流程

  1. Pod 启动

  2. Startup Probe 开始执行

    (如有配置)

    • 若失败,继续重试,直到超时
    • 若成功,标记 Pod 已启动
  3. Readiness Probe 开始执行

    • 成功 → Pod 加入 Service Endpoints,开始接收流量
    • 失败 → 从 Endpoints 移除,不接收新流量
  4. Liveness Probe 开始执行

    • 失败 → 重启容器
    • 成功 → 继续运行

即使 Readiness 失败,只要 Liveness 成功,容器就不会重启------ 这是两者的核心区别。

注意 Readiness 探针 和 Liveness 探针 是同时启用的, 并且 两者各自的 initialDelaySeconds 都从这一刻开始计时,并且探针将持续进行 探测下去,根据 periodSeconds 时间 循环探测

探针类型支持

Kubernetes 支持以下三种探针执行方式:

类型 说明
exec 在容器内执行命令,退出码为 0 表示成功
httpGet 发起 HTTP GET 请求,状态码 2xx/3xx 表示成功
tcpSocket 尝试建立 TCP 连接,成功建立即表示健康
grpc 是(需实现 gRPC 健康协议),应用是基于 gRPC 构建的

最佳实践建议

  1. 为所有关键服务配置 Readiness Probe,避免流量打到未就绪实例。
  2. 谨慎使用 Liveness Probe,确保探针逻辑不会因临时故障导致不必要的重启。
  3. 慢启动应用务必配置 Startup Probe,防止被 Liveness 误杀。
  4. 合理设置 initialDelaySecondsperiodSecondsfailureThreshold 等参数,平衡响应速度与稳定性。
  5. 健康检查端点应轻量、快速、无副作用。

探针配置核心原则

探针类型 目标 配置哲学
startupProbe 等应用"完全启动" 宽限时间要长,避免慢启动被误杀
readinessProbe 判断能否接流量 灵敏但不敏感,依赖失败时快速摘流
livenessProbe 判断是否该重启 保守!宁可晚重启,不要乱重启

⚠️ 永远不要让 livenessProbereadinessProbe 更敏感!

更敏感通常指:

  • 更容易失败(比如超时更短、失败阈值更低、探测频率更高)
  • 更快触发负面动作(如重启容器 或 摘除流量)

场景举例:

  • 应用连接的 Redis 短暂超时(500ms 延迟)。
  • livenessProbe 配置:timeoutSeconds: 1, failureThreshold: 2
  • readinessProbe 配置:timeoutSeconds: 3, failureThreshold: 3

结果:

  • livenessProbe 先失败(2 次 1 秒超时)→ Kubernetes 重启容器!
  • 而其实应用只是暂时不能服务,完全可以通过摘流恢复。

后果:

  1. 不必要的重启:应用本可自愈,却被强制重启,延长恢复时间。
  2. 雪崩风险:如果多个 Pod 因同样原因被同时重启,可能导致整个服务不可用。
  3. 状态丢失:有状态应用(如缓存、长连接)重启后数据丢失。
  4. 与 readiness 设计初衷冲突:readiness 的存在就是为了"隔离问题而不重启"。

上面的设置就是不合理的。

比如下面的例子:

ready 探针 设置相对比较合理 , 超时时间段,检测周期也非常短,失败阀值也比 livessness 小, 这个 ready 探针 就是比liveness 更加敏感。

因为ready 探针,Pod 会被从 Service 的 Endpoints 中移除,不会再让pod 接收流量, 此时容器可能并不需要重启。有可能因为网络波动引起的探测失败,说不定下一个周期 又能自动恢复了。

yaml 复制代码
# readiness:灵敏,快速摘流
readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 10
  periodSeconds: 5
  timeoutSeconds: 2      # 较短超时
  failureThreshold: 2    # 快速失败

# liveness:保守,避免误杀
livenessProbe:
  httpGet:
    path: /live
    port: 8080
  initialDelaySeconds: 60
  periodSeconds: 30
  timeoutSeconds: 5      # 更长超时
  failureThreshold: 3    # 容忍多次失败

探针配置实战

这里使用 http Get 请求来配置探针, 首先应用层 要提供三个http 的api 接口

我这里定义为 /startup/ /health/ , /ready/ 分别对应为启动探针, 存活探针,就绪探针

对于Django的应用

在 项目主目录 创建一个 probes.py

python 复制代码
from django.http import JsonResponse
from django.db import connection
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
import logging

logger = logging.getLogger(__name__)


@csrf_exempt
@require_http_methods(["GET"])
def healthz(request):
    """
    Liveness probe: 只检查进程是否活着,不查外部依赖。
    """
    logger.info("Liveness check")
    return JsonResponse({"status": "alive"}, status=200)


@csrf_exempt
@require_http_methods(["GET"])
def ready(request):
    """
    Readiness probe: 检查关键依赖(如数据库)。
    """
    try:
        with connection.cursor() as cursor:
            cursor.execute("SELECT 1")
        return JsonResponse({"status": "ready"}, status=200)
    except Exception as e:
        logger.error("Readiness check failed: %s", e)
        return JsonResponse({"status": "not ready", "error": str(e)}, status=503)


@csrf_exempt
@require_http_methods(["GET"])
def startup(request):
    """
    Startup probe: 可与 liveness 共用,或做更宽松检查。
    这里我们让它和 liveness 一样,只确认进程运行。
    """
    return JsonResponse({"status": "starting"}, status=200)

在urls.py 添加路由

python 复制代码
from django.urls import path
from . import probes

# 整个项目的总路由进行分发
urlpatterns = [
    # probes relation
    path('health/', probes.healthz),
    path('ready/', probes.ready),
    path('startup/', probes.startup),

]
FastAPI 应用

probes.py

python 复制代码
from fastapi import APIRouter, HTTPException, status
from fastapi.responses import JSONResponse

from base.db import db_manager
from base.logging import logger

router = APIRouter()


@router.get("/health/", status_code=status.HTTP_200_OK)
async def health():
    logger.info("health check")
    return JSONResponse(content={"status": "alive"})


@router.get("/ready/", status_code=status.HTTP_200_OK)
async def ready():
    # 可以在这里添加数据库、缓存等依赖检查
    # 示例:简单返回 ready,后续可扩展
    logger.info("ready check")

    # 获取所有依赖的状态 mock
    status_info = db_manager.get_status()
    logger.info(f"status_info: {status_info}")
    # 定义必须连接的关键服务
    required_services = ["elasticsearch", "mongodb", "redis", "postgresql"]

    # 检查是否有任何关键服务断开
    for service in required_services:
        if status_info.get(service, "") == "disconnected":
            logger.warning(f"service:{service} failed")
            raise HTTPException(
                status_code=503, detail=f"Service {service} is disconnected"
            )
    # 所有服务正常,返回 ready
    return JSONResponse(content={"status": "ready"}, status_code=status.HTTP_200_OK)


@router.get("/startup/", status_code=status.HTTP_200_OK)
async def startup():
    logger.info("startup check")
    return JSONResponse(content={"status": "starting"}, status_code=status.HTTP_200_OK)

在入口文件 app.py

python 复制代码
from probes import router as health_router

app = FastAPI(lifespan=lifespan)

# ...
# 引入路由
app.include_router(health_router)
deployment配置文件
yaml 复制代码
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    k8s.kuboard.cn/displayName: 算法-合同审查服务
    k8s.kuboard.cn/workload: contract-review-svc
  labels:
    k8s.kuboard.cn/layer: svc
    k8s.kuboard.cn/name: contract-review-svc
  name: contract-review-svc
  namespace: prod
spec:
  minReadySeconds: 10
  progressDeadlineSeconds: 600
  replicas: 3
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      k8s.kuboard.cn/layer: svc
      k8s.kuboard.cn/name: contract-review-svc
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        k8s.kuboard.cn/layer: svc
        k8s.kuboard.cn/name: contract-review-svc
        pod-template-hash: 7b847c7476
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: env
                operator: In
                values:
                - prod_high
            weight: 80
          - preference:
              matchExpressions:
              - key: env
                operator: In
                values:
                - prod
            weight: 20
      containers:
      - command:
        - gunicorn
        - main:app
        - -c
        - gunicorn.conf.py
        env:
        - name: TZ
          value: Asia/Shanghai
        image: zhihe-acr-registry-vpc.cn-shanghai.cr.aliyuncs.com/xxxxxx/contract-review-service:xxxxxxx-xxxxx
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              command:
              - sleep
              - "600"
        livenessProbe:
          failureThreshold: 2
          httpGet:
            path: /health/
            port: 8090
            scheme: HTTP
          initialDelaySeconds: 30
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 1
        name: contract-review
        ports:
        - containerPort: 8090
          name: c-review
          protocol: TCP
        readinessProbe:
          failureThreshold: 2
          httpGet:
            path: /ready/
            port: 8090
            scheme: HTTP
          initialDelaySeconds: 5
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          limits:
            cpu: "2"
            memory: 3000Mi
          requests:
            cpu: 1500m
            memory: 2000Mi
        startupProbe:
          failureThreshold: 20
          httpGet:
            path: /startup/
            port: 8090
            scheme: HTTP
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
          timeoutSeconds: 2
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /usr/src/app/logs
          name: volume-3wnyy
        - mountPath: /usr/src/app/.env
          name: volume-35k4e
          readOnly: true
          subPath: .env
        - mountPath: /usr/src/app/gunicorn.conf.py
          name: volume-3ydcp
          readOnly: true
          subPath: gunicorn.conf.py
        - mountPath: /usr/src/app/config/config.ini
          name: volume-35k4e
          readOnly: true
          subPath: config.ini
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: acr-zhihe-secret-internal
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 660
      volumes:
      - hostPath:
          path: /tmp/logs/prod/contract-review-svc
          type: DirectoryOrCreate
        name: volume-3wnyy
      - configMap:
          defaultMode: 420
          items:
          - key: .env
            path: .env
          - key: config.ini
            path: config.ini
          name: contract-review
        name: volume-35k4e
      - configMap:
          defaultMode: 420
          items:
          - key: gunicorn.conf.py
            path: gunicorn.conf.py
          name: contract-review
        name: volume-3ydcp

这样一个基本上完整的配置 就已经可以了,当然根据应用的不同 ,可以调节不同的参数。

总结

Kubernetes 的探针机制是实现自愈、弹性、高可用微服务架构的关键组件。通过合理配置 Liveness、Readiness 和 Startup 探针,你可以:

  • 自动恢复故障实例
  • 保障服务流量只打到健康节点
  • 容忍慢启动应用的初始化过程

掌握这三种探针的原理与使用方法,是每一位 Kubernetes 开发者和运维工程师的必备技能。

官方文档

liveness-probe

configure-liveness-readiness-startup-probes
分享快乐,留住感动. '2026-01-06 22:24:42' --frank

相关推荐
Hui Baby1 天前
K8S管理GPU等简述
云原生·容器·kubernetes
赵文宇(温玉)1 天前
Docker是时代发展的产物
运维·docker·容器
赵文宇(温玉)1 天前
Docker发展时间线(2008~2025)
运维·docker·容器
牛奔1 天前
Kubernetes 节点安全维护全流程:从驱逐 Pod 到彻底清理残留
java·安全·云原生·容器·kubernetes
草木红1 天前
Docker 和 portainer 安装
运维·docker·容器·portainer
伞啊伞1 天前
k8s(三)操作管理
云原生·容器·kubernetes
x10n91 天前
理解K8s动态准入控制器-基于Admission Webhook实现Sidecar自动注入检验等
云原生·容器·kubernetes·k8s准入控制器
LucidX1 天前
Kubernetes集群架构与组件
容器·架构·kubernetes
Qianliwind1 天前
安卓手机作为服务器安装docker安装外网可访问网站
服务器·docker·容器