Kubernetes 探针完全指南:健康检查机制深度解析
本文深入剖析 Kubernetes 三种探针(livenessProbe、readinessProbe、startupProbe)的核心技术,涵盖探针架构设计、配置方式详解、探测机制原理、YAML 字段说明,以及生产环境最佳实践。掌握探针是确保应用高可用的关键一步。
目录
一、为什么需要探针?
1.1 没有探针的问题
| 问题 | 说明 | 后果 |
|---|---|---|
| 假健康 | 容器运行但应用未就绪 | 流量发送到未就绪实例 |
| 死锁 | 进程存在但无法响应 | 请求超时、服务不可用 |
| 慢启动 | 应用启动需要时间 | 过早接收流量导致失败 |
| 资源泄漏 | 应用异常但进程不退出 | 内存耗尽、节点崩溃 |
1.2 探针的价值
#mermaid-svg-PNWTaJ0G3Q4pq1rs{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .error-icon{fill:#552222;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .marker.cross{stroke:#333333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs p{margin:0;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .cluster-label text{fill:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .cluster-label span{color:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .cluster-label span p{background-color:transparent;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .label text,#mermaid-svg-PNWTaJ0G3Q4pq1rs span{fill:#333;color:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .node rect,#mermaid-svg-PNWTaJ0G3Q4pq1rs .node circle,#mermaid-svg-PNWTaJ0G3Q4pq1rs .node ellipse,#mermaid-svg-PNWTaJ0G3Q4pq1rs .node polygon,#mermaid-svg-PNWTaJ0G3Q4pq1rs .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .rough-node .label text,#mermaid-svg-PNWTaJ0G3Q4pq1rs .node .label text,#mermaid-svg-PNWTaJ0G3Q4pq1rs .image-shape .label,#mermaid-svg-PNWTaJ0G3Q4pq1rs .icon-shape .label{text-anchor:middle;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .rough-node .label,#mermaid-svg-PNWTaJ0G3Q4pq1rs .node .label,#mermaid-svg-PNWTaJ0G3Q4pq1rs .image-shape .label,#mermaid-svg-PNWTaJ0G3Q4pq1rs .icon-shape .label{text-align:center;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .node.clickable{cursor:pointer;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .arrowheadPath{fill:#333333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PNWTaJ0G3Q4pq1rs .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PNWTaJ0G3Q4pq1rs .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PNWTaJ0G3Q4pq1rs .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .cluster text{fill:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .cluster span{color:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PNWTaJ0G3Q4pq1rs rect.text{fill:none;stroke-width:0;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .icon-shape,#mermaid-svg-PNWTaJ0G3Q4pq1rs .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .icon-shape p,#mermaid-svg-PNWTaJ0G3Q4pq1rs .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .icon-shape .label rect,#mermaid-svg-PNWTaJ0G3Q4pq1rs .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PNWTaJ0G3Q4pq1rs .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PNWTaJ0G3Q4pq1rs .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PNWTaJ0G3Q4pq1rs :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 探针
存活检测
就绪检测
启动检测
自动重启
流量控制
保护慢启动
核心能力:
- 自动检测:无需人工干预
- 快速响应:及时发现问题
- 流量控制:确保流量只到健康实例
- 自愈能力:自动重启故障容器
1.3 探针对比
| 特性 | livenessProbe | readinessProbe | startupProbe |
|---|---|---|---|
| 目的 | 检测是否存活 | 检测是否就绪 | 检测是否启动完成 |
| 失败后果 | 重启容器 | 移除流量 | 重启容器 |
| 执行时机 | 容器启动后 | 容器启动后 | 容器启动时 |
| 适用场景 | 死锁检测 | 流量控制 | 慢启动保护 |
| 必要性 | 强烈推荐 | 强烈推荐 | 可选 |
二、三种探针详解
2.1 Liveness Probe(存活探针)
作用:检测容器是否存活,失败则重启容器。
yaml
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
适用场景:
- 应用死锁检测
- 内存泄漏检测
- 进程假死检测
注意事项:
- 不要检测外部依赖(数据库、缓存)
- 探测逻辑要轻量
- 避免误杀健康容器
2.2 Readiness Probe(就绪探针)
作用:检测容器是否就绪,失败则从 Service 移除。
yaml
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
适用场景:
- 应用启动完成检测
- 依赖服务可用性检测
- 流量控制
注意事项:
- 检测应用是否准备好接收流量
- 可以检测外部依赖
- 失败不会重启容器
2.3 Startup Probe(启动探针)
作用:检测容器是否启动完成,保护慢启动容器。
yaml
startupProbe:
httpGet:
path: /startup
port: 8080
failureThreshold: 30
periodSeconds: 10
适用场景:
- 应用启动时间较长(>60秒)
- 需要初始化数据的应用
- 避免被 livenessProbe 误杀
注意事项:
- 成功前其他探针不执行
- 失败会重启容器
- 成功后不再执行
三、探测方式详解
3.1 HTTP GET 探测
yaml
httpGet:
path: /healthz # 探测路径
port: 8080 # 端口
host: localhost # 主机(可选)
scheme: HTTP # HTTP/HTTPS
httpHeaders: # 自定义请求头
- name: Authorization
value: Bearer token123
成功条件:HTTP 状态码 200-399
适用场景:Web 应用、API 服务
3.2 TCP Socket 探测
yaml
tcpSocket:
port: 3306 # 探测端口
host: localhost # 主机(可选)
成功条件:TCP 连接建立成功
适用场景:数据库、缓存、非 HTTP 服务
3.3 Exec 命令探测
yaml
exec:
command:
- /bin/sh
- -c
- |
mysqladmin ping -h localhost -uroot -p$MYSQL_ROOT_PASSWORD
成功条件:命令退出码为 0
适用场景:复杂检测逻辑、特定应用检查
3.4 GRPC 探测(K8s 1.24+)
yaml
grpc:
port: 2379
service: etcd.etcd.kube-system.svc.cluster.local
成功条件:gRPC 健康检查成功
适用场景:gRPC 服务
3.5 探测方式对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| HTTP GET | 简单直观 | 需要 HTTP 端点 | Web 应用 |
| TCP Socket | 通用 | 无法检测应用层 | 数据库 |
| Exec | 灵活 | 需要脚本 | 复杂检查 |
| GRPC | 原生支持 | 版本要求 | gRPC 服务 |
四、探针配置参数
4.1 通用参数
| 参数 | 默认值 | 说明 |
|---|---|---|
initialDelaySeconds |
0 | 启动后等待时间 |
periodSeconds |
10 | 探测间隔 |
timeoutSeconds |
1 | 超时时间 |
successThreshold |
1 | 成功阈值 |
failureThreshold |
3 | 失败阈值 |
4.2 参数详解
yaml
livenessProbe:
httpGet:
path: /healthz
port: 8080
# 初始延迟:容器启动后等待 30 秒才开始探测
initialDelaySeconds: 30
# 探测间隔:每 10 秒探测一次
periodSeconds: 10
# 超时时间:探测请求超过 5 秒视为失败
timeoutSeconds: 5
# 成功阈值:连续成功 1 次视为成功
successThreshold: 1
# 失败阈值:连续失败 3 次视为失败
failureThreshold: 3
4.3 参数配置建议
yaml
# 快速失败(适合快速检测问题)
livenessProbe:
periodSeconds: 5
timeoutSeconds: 2
failureThreshold: 3
# 慢速检测(适合避免误判)
livenessProbe:
periodSeconds: 30
timeoutSeconds: 10
failureThreshold: 5
# 就绪检测(快速响应)
readinessProbe:
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 2
# 启动检测(耐心等待)
startupProbe:
periodSeconds: 10
failureThreshold: 30 # 最长等待 300 秒
五、探针与生命周期
5.1 容器生命周期
#mermaid-svg-DTPz7yck6tLD1CE5{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-DTPz7yck6tLD1CE5 .error-icon{fill:#552222;}#mermaid-svg-DTPz7yck6tLD1CE5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-DTPz7yck6tLD1CE5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-DTPz7yck6tLD1CE5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-DTPz7yck6tLD1CE5 .marker.cross{stroke:#333333;}#mermaid-svg-DTPz7yck6tLD1CE5 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-DTPz7yck6tLD1CE5 p{margin:0;}#mermaid-svg-DTPz7yck6tLD1CE5 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 .cluster-label text{fill:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 .cluster-label span{color:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 .cluster-label span p{background-color:transparent;}#mermaid-svg-DTPz7yck6tLD1CE5 .label text,#mermaid-svg-DTPz7yck6tLD1CE5 span{fill:#333;color:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 .node rect,#mermaid-svg-DTPz7yck6tLD1CE5 .node circle,#mermaid-svg-DTPz7yck6tLD1CE5 .node ellipse,#mermaid-svg-DTPz7yck6tLD1CE5 .node polygon,#mermaid-svg-DTPz7yck6tLD1CE5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-DTPz7yck6tLD1CE5 .rough-node .label text,#mermaid-svg-DTPz7yck6tLD1CE5 .node .label text,#mermaid-svg-DTPz7yck6tLD1CE5 .image-shape .label,#mermaid-svg-DTPz7yck6tLD1CE5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-DTPz7yck6tLD1CE5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-DTPz7yck6tLD1CE5 .rough-node .label,#mermaid-svg-DTPz7yck6tLD1CE5 .node .label,#mermaid-svg-DTPz7yck6tLD1CE5 .image-shape .label,#mermaid-svg-DTPz7yck6tLD1CE5 .icon-shape .label{text-align:center;}#mermaid-svg-DTPz7yck6tLD1CE5 .node.clickable{cursor:pointer;}#mermaid-svg-DTPz7yck6tLD1CE5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-DTPz7yck6tLD1CE5 .arrowheadPath{fill:#333333;}#mermaid-svg-DTPz7yck6tLD1CE5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-DTPz7yck6tLD1CE5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-DTPz7yck6tLD1CE5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DTPz7yck6tLD1CE5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-DTPz7yck6tLD1CE5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DTPz7yck6tLD1CE5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-DTPz7yck6tLD1CE5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-DTPz7yck6tLD1CE5 .cluster text{fill:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 .cluster span{color:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-DTPz7yck6tLD1CE5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-DTPz7yck6tLD1CE5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-DTPz7yck6tLD1CE5 .icon-shape,#mermaid-svg-DTPz7yck6tLD1CE5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-DTPz7yck6tLD1CE5 .icon-shape p,#mermaid-svg-DTPz7yck6tLD1CE5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-DTPz7yck6tLD1CE5 .icon-shape .label rect,#mermaid-svg-DTPz7yck6tLD1CE5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-DTPz7yck6tLD1CE5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-DTPz7yck6tLD1CE5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-DTPz7yck6tLD1CE5 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 成功
失败
成功
失败
失败
容器创建
InitContainer 执行
主容器启动
startupProbe 执行
livenessProbe 开始
重启容器
readinessProbe 开始
加入 Service
从 Service 移除
5.2 探针执行时序
| 阶段 | livenessProbe | readinessProbe | startupProbe |
|---|---|---|---|
| 容器启动 | 等待 initialDelaySeconds | 等待 initialDelaySeconds | 立即开始 |
| startupProbe 执行中 | 不执行 | 不执行 | 执行 |
| startupProbe 成功 | 开始执行 | 开始执行 | 停止 |
| startupProbe 失败 | 不执行 | 不执行 | 重启容器 |
| livenessProbe 失败 | 重启容器 | 继续执行 | - |
| readinessProbe 失败 | 继续执行 | 移除流量 | - |
5.3 与 Service 的关系
yaml
# Service 只转发到就绪的 Pod
apiVersion: v1
kind: Service
metadata:
name: web-service
spec:
selector:
app: web
ports:
- port: 80
targetPort: 8080
关键机制:
- Pod 创建后,readinessProbe 开始执行
- 只有 readinessProbe 成功的 Pod 才会加入 Service 的 Endpoints
- readinessProbe 失败的 Pod 会被临时移除
- readinessProbe 恢复后,Pod 重新加入
六、实战:生产级探针配置
6.1 完整示例:Web 应用
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web-server
image: nginx:1.25.3
ports:
- name: http
containerPort: 80
# 启动探针:给应用足够时间启动
startupProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30 # 最多等待 10 + 30*5 = 160 秒
# 存活探针:检测应用是否存活
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
# 就绪探针:检测应用是否就绪
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
6.2 数据库探针配置
yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql
replicas: 1
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
# 启动探针:等待 MySQL 初始化完成
startupProbe:
exec:
command:
- /bin/sh
- -c
- |
mysqladmin ping -h localhost -uroot -p$MYSQL_ROOT_PASSWORD
initialDelaySeconds: 20
periodSeconds: 10
failureThreshold: 30 # 最多等待 20 + 30*10 = 320 秒
# 存活探针:检测 MySQL 是否存活
livenessProbe:
exec:
command:
- mysqladmin
- ping
- -h
- localhost
- -uroot
- -p$MYSQL_ROOT_PASSWORD
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 就绪探针:检测 MySQL 是否就绪
readinessProbe:
exec:
command:
- /bin/sh
- -c
- |
mysql -h localhost -uroot -p$MYSQL_ROOT_PASSWORD -e "SELECT 1"
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
6.3 Redis 探针配置
yaml
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis:7.0
# 启动探针
startupProbe:
tcpSocket:
port: 6379
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
# 存活探针
livenessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 20
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 就绪探针
readinessProbe:
exec:
command:
- redis-cli
- ping
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
6.4 Java 应用探针配置
yaml
apiVersion: v1
kind: Pod
metadata:
name: java-app
spec:
containers:
- name: app
image: java-app:1.0
# 使用 Spring Boot Actuator
startupProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
failureThreshold: 60
periodSeconds: 10
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 60
periodSeconds: 15
timeoutSeconds: 5
failureThreshold: 5
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 3
failureThreshold: 3
七、常用命令速查
7.1 查看探针配置
bash
# 查看 Pod 详情(包含探针配置)
kubectl describe pod <pod-name>
# 查看探针配置(JSON 格式)
kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].livenessProbe}'
# 查看探针状态
kubectl get pod <pod-name> -o jsonpath='{.status.containerStatuses[*].state}'
7.2 排查探针问题
bash
# 1. 查看 Pod 事件
kubectl describe pod <pod-name> | grep -A10 Events
# 2. 查看容器日志
kubectl logs <pod-name> --previous # 查看重启前的日志
# 3. 查看容器状态
kubectl get pod <pod-name> -o wide
# 4. 进入容器手动测试
kubectl exec -it <pod-name> -- /bin/bash
# 手动执行探针命令
curl localhost:8080/healthz
mysqladmin ping -h localhost
redis-cli ping
# 5. 实时监控探针状态
kubectl get pod <pod-name> -w
7.3 常见探针错误
| 错误 | 原因 | 解决方案 |
|---|---|---|
CrashLoopBackOff |
livenessProbe 失败 | 检查应用健康,调整探针 |
Readiness probe failed |
readinessProbe 失败 | 检查应用就绪状态 |
Startup probe failed |
startupProbe 失败 | 检查启动逻辑 |
Liveness probe failed |
livenessProbe 失败 | 应用可能死锁或崩溃 |
八、最佳实践与避坑指南
8.1 必须遵守的原则
| 原则 | 说明 | 示例 |
|---|---|---|
| 区分存活和就绪 | 不同探针不同用途 | liveness ≠ readiness |
| 探针要轻量 | 避免复杂计算 | 简单 HTTP GET |
| 合理设置阈值 | 避免误判 | failureThreshold: 3 |
| 使用启动探针 | 保护慢启动应用 | startupProbe |
| 避免外部依赖 | liveness 不检测外部服务 | 只检测自身 |
8.2 常见错误
错误 1:livenessProbe 检测外部依赖
yaml
# ❌ 错误:数据库不可用导致容器重启
livenessProbe:
exec:
command:
- /bin/sh
- -c
- |
mysql -h db-service -e "SELECT 1"
# ✅ 正确:只检测自身健康
livenessProbe:
exec:
command:
- /bin/sh
- -c
- |
# 检测进程是否存在
ps aux | grep app
错误 2:探针过于频繁
yaml
# ❌ 错误:过于频繁,增加系统负担
periodSeconds: 1
timeoutSeconds: 1
# ✅ 正确:合理频率
periodSeconds: 10
timeoutSeconds: 5
错误 3:没有启动探针
yaml
# ❌ 错误:启动时间长,liveness 误杀
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 10 # 启动需要 60 秒
failureThreshold: 3
# ✅ 正确:使用 startupProbe
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 60
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
8.3 探针设计模式
模式 1:独立健康检查端点
python
# 应用代码
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/healthz') # 存活检查
def healthz():
return jsonify({"status": "alive"}), 200
@app.route('/ready') # 就绪检查
def ready():
# 检查依赖服务
if check_database() and check_cache():
return jsonify({"status": "ready"}), 200
else:
return jsonify({"status": "not_ready"}), 503
模式 2:使用 Spring Boot Actuator
yaml
# application.yaml
management:
endpoints:
web:
exposure:
include: health,info,metrics
endpoint:
health:
probes:
enabled: true
group:
liveness:
include: livenessState
readiness:
include: readinessState,db
模式 3:自定义探针脚本
bash
#!/bin/bash
# health-check.sh
# 检查进程
if ! pgrep -f "my-app" > /dev/null; then
echo "Process not running"
exit 1
fi
# 检查端口
if ! nc -z localhost 8080; then
echo "Port not listening"
exit 1
fi
# 检查日志
if grep -q "FATAL ERROR" /var/log/app.log; then
echo "Fatal error in logs"
exit 1
fi
echo "Healthy"
exit 0
8.4 性能优化建议
yaml
# 1. 使用 TCP 探测代替 HTTP(性能更好)
readinessProbe:
tcpSocket:
port: 8080
periodSeconds: 10
# 2. 合理设置超时
timeoutSeconds: 5 # 不要太小(网络波动)
# 也不要太大(响应慢)
# 3. 使用更长的间隔减少负载
periodSeconds: 30 # 对于稳定的应用
# 4. 利用 initialDelaySeconds 避免启动期探测
initialDelaySeconds: 60 # 给应用足够启动时间
九、总结
9.1 核心要点回顾
- 三种探针各司其职:liveness 保活、readiness 控流、startup 护启动
- 探测方式要合适:HTTP、TCP、Exec 根据场景选择
- 参数配置要合理:避免误判和过度探测
- 启动探针很重要:保护慢启动应用
- 探针与 Service 联动:确保流量只到健康实例
9.2 探针配置清单
yaml
# 完整的探针配置模板
startupProbe: # 启动探针(可选)
httpGet:
path: /startup
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
failureThreshold: 30
livenessProbe: # 存活探针(必须)
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
successThreshold: 1
readinessProbe: # 就绪探针(必须)
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
successThreshold: 1
9.3 学习路线
探针基础 → Deployment 滚动更新 → Service 流量管理
↓
PodDisruptionBudget → HPA 自动扩缩容 → 混沌工程
9.4 下一步学习
- PodDisruptionBudget:优雅处理节点维护
- HPA 深入:基于自定义指标的扩缩容
- Service Mesh:更高级的健康检查
- 混沌工程:Chaos Mesh 故障注入
- 可观测性:Prometheus 监控探针
附录:完整示例汇总
生产级探针完整配置
yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: production-app
namespace: production
spec:
replicas: 3
selector:
matchLabels:
app: production-app
template:
metadata:
labels:
app: production-app
spec:
containers:
- name: app
image: myapp:1.0.0
ports:
- name: http
containerPort: 8080
# 启动探针
startupProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 30
# 存活探针
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
# 就绪探针
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 3
failureThreshold: 3
# 资源限制
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "256Mi"
# 优雅终止
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 10"]
验证测试
bash
# 1. 创建 Deployment
kubectl apply -f probe-demo.yaml
# 2. 查看 Pod 状态
kubectl get pods -n production -w
# 3. 查看探针配置
kubectl describe pod <pod-name> -n production | grep -A5 "Probe"
# 4. 测试探针
# 模拟探针失败
kubectl exec -it <pod-name> -n production -- /bin/bash
# 停止应用进程
kill 1 # 观察 livenessProbe 是否重启容器
# 5. 查看事件
kubectl get events -n production --sort-by='.lastTimestamp'
# 6. 查看重启次数
kubectl get pod <pod-name> -n production -o jsonpath='{.status.containerStatuses[*].restartCount}'