文章目录
-
- [深入理解 Kubernetes 中的探针](#深入理解 Kubernetes 中的探针)
-
- 为什么需要探针?
- [1. Liveness Probe(存活探针)](#1. Liveness Probe(存活探针))
- [2. Readiness Probe(就绪探针)](#2. Readiness Probe(就绪探针))
- [3. Startup Probe(启动探针)](#3. Startup Probe(启动探针))
- 三者协同工作流程
- 探针类型支持
- 最佳实践建议
- 探针配置核心原则
- 探针配置实战
-
- 对于Django的应用
- [FastAPI 应用](#FastAPI 应用)
- deployment配置文件
- 总结
- 官方文档
深入理解 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"})
这样的问题 会出现 雪崩式重启
- 数据库短暂不可用(网络抖动、主从切换)
- 所有 Pod 的
livenessProbe失败 - Kubernetes 重启所有容器
- 容器重启后又连不上 DB → 再次失败 → 再次重启
- 整个服务彻底不可用,即使 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 被重启。
三者协同工作流程
-
Pod 启动
-
Startup Probe 开始执行
(如有配置)
- 若失败,继续重试,直到超时
- 若成功,标记 Pod 已启动
-
Readiness Probe 开始执行
- 成功 → Pod 加入 Service Endpoints,开始接收流量
- 失败 → 从 Endpoints 移除,不接收新流量
-
Liveness Probe 开始执行
- 失败 → 重启容器
- 成功 → 继续运行
即使 Readiness 失败,只要 Liveness 成功,容器就不会重启------ 这是两者的核心区别。
注意 Readiness 探针 和 Liveness 探针 是同时启用的, 并且 两者各自的 initialDelaySeconds 都从这一刻开始计时,并且探针将持续进行 探测下去,根据 periodSeconds 时间 循环探测
探针类型支持
Kubernetes 支持以下三种探针执行方式:
| 类型 | 说明 |
|---|---|
exec |
在容器内执行命令,退出码为 0 表示成功 |
httpGet |
发起 HTTP GET 请求,状态码 2xx/3xx 表示成功 |
tcpSocket |
尝试建立 TCP 连接,成功建立即表示健康 |
grpc |
是(需实现 gRPC 健康协议),应用是基于 gRPC 构建的 |
最佳实践建议
- 为所有关键服务配置 Readiness Probe,避免流量打到未就绪实例。
- 谨慎使用 Liveness Probe,确保探针逻辑不会因临时故障导致不必要的重启。
- 慢启动应用务必配置 Startup Probe,防止被 Liveness 误杀。
- 合理设置
initialDelaySeconds、periodSeconds、failureThreshold等参数,平衡响应速度与稳定性。 - 健康检查端点应轻量、快速、无副作用。
探针配置核心原则
| 探针类型 | 目标 | 配置哲学 |
|---|---|---|
startupProbe |
等应用"完全启动" | 宽限时间要长,避免慢启动被误杀 |
readinessProbe |
判断能否接流量 | 灵敏但不敏感,依赖失败时快速摘流 |
livenessProbe |
判断是否该重启 | 保守!宁可晚重启,不要乱重启 |
⚠️ 永远不要让
livenessProbe比readinessProbe更敏感!
更敏感通常指:
- 更容易失败(比如超时更短、失败阈值更低、探测频率更高)
- 更快触发负面动作(如重启容器 或 摘除流量)
场景举例:
- 应用连接的 Redis 短暂超时(500ms 延迟)。
livenessProbe配置:timeoutSeconds: 1,failureThreshold: 2readinessProbe配置:timeoutSeconds: 3,failureThreshold: 3
结果:
livenessProbe先失败(2 次 1 秒超时)→ Kubernetes 重启容器!- 而其实应用只是暂时不能服务,完全可以通过摘流恢复。
后果:
- 不必要的重启:应用本可自愈,却被强制重启,延长恢复时间。
- 雪崩风险:如果多个 Pod 因同样原因被同时重启,可能导致整个服务不可用。
- 状态丢失:有状态应用(如缓存、长连接)重启后数据丢失。
- 与 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 开发者和运维工程师的必备技能。
官方文档
configure-liveness-readiness-startup-probes
分享快乐,留住感动. '2026-01-06 22:24:42' --frank