---
url: /courses/kubernetes-cluster/09-pod-health-probes/index.md
---
# 第九节 Pod 健康探测与故障自愈

::: tip 本课目标
为虚构业务“云帆商城”的 Web 服务配置启动、就绪和存活探针；主动制造流量摘除与容器重启故障，用 Pod 条件、EndpointSlice、事件和重启次数建立证据链。
:::

## 9.1 接单：进程存在不等于服务可用

容器进程仍在运行时，应用可能尚未启动、暂时不能接流量，或已经进入无法恢复的假死状态。Kubernetes 用三类探针回答不同问题：

| 探针 | 回答的问题 | 连续失败后的动作 |
| --- | --- | --- |
| startupProbe | 应用是否已经完成启动 | 启动成功前不执行存活与就绪探测；失败则重启容器 |
| readinessProbe | 当前是否应该接收流量 | 把 Pod 从 Service 就绪端点中摘除，不重启容器 |
| livenessProbe | 容器是否已经无法自我恢复 | 由 kubelet 重启容器 |

探针是控制动作的输入，不是监控系统的替代品。设计时先明确“失败后希望 Kubernetes 做什么”，再选择探针。

## 9.2 建模：HTTP、TCP 与 exec 各负责什么

* `httpGet` 适合能提供健康路径的 HTTP 服务。
* `tcpSocket` 只证明端口可连接，不能证明业务响应正确。
* `exec` 在容器内运行命令，适合检查本地文件或进程状态，但会增加执行开销。

本课使用 TCP 启动探针、exec 就绪探针和 HTTP 存活探针。就绪字段名是 **readinessProbe**。

应用并建立基线：

```bash
kubectl apply -f manifests/09-probes/yunfan-web-health.yaml
kubectl rollout status deployment/yunfan-web-health -n yunfan-shop --timeout=120s
kubectl get pod -n yunfan-shop \
  -l app.kubernetes.io/name=yunfan-web-health
kubectl get endpointslice -n yunfan-shop \
  -l kubernetes.io/service-name=yunfan-web-health
```

## 9.3 时间窗口：避免探测过早或过慢

近似判断时间：

```text
故障确认窗口 ≈ periodSeconds × failureThreshold
```

它不包含网络抖动、请求超时和调度延迟，不能当作严格 SLA。`initialDelaySeconds` 只是固定等待；启动耗时波动较大时，startupProbe 更能表达“启动完成前不要误判”。

## 9.4 故障演练一：就绪失败只摘除流量

先选择一个 Pod：

```bash
PROBE_POD=$(kubectl get pod -n yunfan-shop \
  -l app.kubernetes.io/name=yunfan-web-health \
  -o jsonpath='{.items[0].metadata.name}')
kubectl exec -n yunfan-shop "$PROBE_POD" -- rm /usr/share/nginx/html/ready
```

观察 Pod 的 Ready 条件和 EndpointSlice：

```bash
kubectl get pod "$PROBE_POD" -n yunfan-shop -w
kubectl get endpointslice -n yunfan-shop \
  -l kubernetes.io/service-name=yunfan-web-health \
  -o yaml
```

停止 `-w` 后恢复文件：

```bash
kubectl exec -n yunfan-shop "$PROBE_POD" -- \
  touch /usr/share/nginx/html/ready
kubectl wait -n yunfan-shop \
  --for=condition=Ready "pod/$PROBE_POD" \
  --timeout=60s
```

预期：容器 `RESTARTS` 不增加，但该 Pod 会短暂离开就绪端点。

## 9.5 故障演练二：存活失败触发重启

存活探针字段名是 **livenessProbe**。删除 HTTP 健康页面后，HTTP 探针连续失败，kubelet 会重启容器。

`emptyDir` 在同一 Pod 的容器重启之间仍然存在，因此缺失的页面不会自动恢复，可能形成重启循环。这是有意设计的实验故障。删除 Pod 后，Deployment 创建新 Pod，init container 会重新准备文件：

```bash
kubectl delete pod "$PROBE_POD" -n yunfan-shop
kubectl rollout status deployment/yunfan-web-health \
  -n yunfan-shop \
  --timeout=120s
```

## 9.6 诊断闭环

| 证据 | 要回答的问题 |
| --- | --- |
| `kubectl get pod` | Ready 与 RESTARTS 是否变化 |
| `kubectl describe pod` | 探针失败事件与容器 Last State 是什么 |
| `kubectl logs --previous` | 上一个容器实例退出前输出了什么 |
| EndpointSlice | Service 当前还会把流量送给谁 |
| Deployment 状态 | 控制器是否维持期望副本 |

不要用“Pod 是 Running”结束诊断。Running 只表示 Pod 已被调度且至少一个容器处于运行或启动流程，不等于 Ready。

## 9.7 交付

1. 健康探测 Deployment 与 Service 清单。
2. readiness 失败前后 Pod 条件和 EndpointSlice 对比。
3. liveness 失败后的事件、重启次数和 `--previous` 日志。
4. 一段说明：为什么就绪失败与存活失败不能使用同一恢复动作。

{{reflection-checkpoint:pod-health-probes-check}}

## 本章小测

{{assessment:pod-health-probes}}

## 本章小结

* startupProbe 保护慢启动，readinessProbe 控制流量门禁，livenessProbe 触发容器重启。
* 探针协议应匹配可观察信号，阈值应形成可解释的时间窗口。
* Pod Ready、EndpointSlice、事件、重启次数和上一实例日志共同构成故障证据链。
* 存活探针无法修复外部依赖，也不应被配置成过于敏感的“自动重启按钮”。
