自愈与故障恢复
本教程共 65 篇 · 第 52 篇 · 更新于 2026-08-14 · 约 16 分钟阅读
本节目标:搞懂 Kubernetes 凭什么”自己修自己”——副本挂了能补、容器崩了能重启、节点没了能挪走,以及这些能力分别由谁在背后默默干活。
前面几十章你建过那么多对象,有没有想过一个问题:Pod 跑着跑着崩了,是谁把它重新拉起来的?节点突然断电,原本上面的副本去哪了?答案就是 Kubernetes 的**自愈(Self-healing)**能力。
这不是魔法,而是一套”有人盯着、发现不对就纠正”的机制。本章把散落在全书的自愈本领串成一条线。
52-1 自愈的本质:调谐循环
Kubernetes 里几乎所有控制器都运行同一个模式——调谐循环(Reconcile Loop):
- 读取你期望的状态(比如 Deployment 说”我要 3 个副本”)。
- 观察集群实际状态(现在只有 2 个在跑)。
- 发现不一致,就采取行动让实际靠拢期望(再起 1 个)。
- 过一会儿再检查,循环往复。
Deployment、ReplicaSet、StatefulSet、DaemonSet……全靠这个循环兜底。所以副本数少了会自动补,多了会自动减。这就是最基础的自愈。
Note调谐循环是”声明式”的核心红利。你只管说”我要什么样”,不用写”怎么修”。控制器永远在努力把现实掰向你写的期望。
52-2 kubelet 守卫着节点上的 Pod
节点上的”现场总指挥”是 kubelet。它盯着本节点每个 Pod 的容器:
- 容器进程退出了?按
restartPolicy重启它。 - 磁盘上的镜像没了?重新拉。
- 节点要关机了?执行节点体面关闭(Graceful Node Shutdown),先通知 Pod 优雅退出。
静态 Pod(第 23 章提过)更特殊:它在节点本地由 kubelet 直接看守,即使 API 服务器连不上,kubelet 也会按本地清单把它跑起来。所以控制平面挂了,关键静态 Pod(如 kube-apiserver 本身)依然能持续服务。
Tip想看自愈现场?故意
kubectl delete pod一个由 Deployment 管的 Pod,再用kubectl get pods观察——新 Pod 几乎立刻被补上。这就是 ReplicaSet 控制器在调谐。
52-3 探针:让自愈更”懂事”
光会重启还不够。有些故障不是”进程崩了”,而是”进程活着但卡死了”。这时要靠第 14 章讲的三种探针:
- livenessProbe(存活探针):失败 = 容器”没救了”,kubelet 按重启策略重启它。这是自愈的”触发器”。
- readinessProbe(就绪探针):失败 = 容器”还没好”,从 Service 端点摘掉,不再接流量,但不重启。等它好了再放回。
- startupProbe(启动探针):给慢启动应用一个”宽限期”,宽限期内别的探针先别急着判死刑。
一个经典自愈链路:
- 应用死锁,liveness 连续失败。
- kubelet 杀掉容器,按
restartPolicy: Always重启。 - 重启后 readiness 还没过,Service 不导流量,避免把请求打给没准备好的实例。
- 应用真正就绪,readiness 通过,重新接流量。
Warning别把 liveness 和 readiness 设成同一个探针。如果共用,一旦就绪失败,liveness 也会失败→不断重启→永远起不来。两者职责不同,务必分开配置。
52-4 重启策略 restartPolicy
Pod 层面的 restartPolicy 决定容器退出的处理方式,只有三个值:
| 值 | 含义 | 典型用途 |
|---|---|---|
Always | 永远重启(默认) | 长期运行的服务 |
OnFailure | 只在非零退出码时重启 | 一次性任务(常配 Job) |
Never | 绝不重启 | 跑完即弃、自己看日志 |
注意:kubelet 的重启是同节点原地重启,不是换节点。如果节点本身坏了,重启也没用——这时要靠控制器把 Pod 调度到别的节点(见下节)。
NoteJob/CronJob(第 22 章)常用
OnFailure或Never,配合任务本身的重试次数,避免无限重启。普通 Deployment 几乎都用Always。
52-5 节点故障:副本会”搬家”
当整个节点失联(宕机、网络隔离),自愈怎么表现?
- 节点控制器(Node Controller)在
node-monitor-grace-period内收不到心跳,把节点标记为NotReady。 - 再经过一段时间,节点上的 Pod 被标记为
Terminating/Unknown。 - 这些 Pod 的 owner(如 Deployment)发现”我的副本少了一块”,于是在别的可用节点上补齐副本。
- 被删的 Pod 如果节点后来恢复,会因 UID 不匹配被当作孤儿清理掉。
这就是”节点没了,副本挪走”的全过程。前提是:你的应用跑了多个副本且分布在不同节点(用第 40 章的反亲和性可以强制分散)。
Tip自愈的前提是”有冗余”。单副本 Deployment 节点一挂就真没了——所以生产服务务必设
replicas ≥ 2,并用反亲和性避免全压一个节点。
52-6 资源压力与节点驱逐
节点资源(CPU/内存/磁盘)吃紧时,kubelet 会触发节点压力驱逐(Node-pressure Eviction):挑出”最该让位”的 Pod 杀掉,腾出资源保住别的。被驱逐的 Pod 同样会被控制器在别处重建。
配合第 15 章的资源请求/限制和 QoS 等级,你能决定”谁先死”:requests 与 limits 相等的是 Guaranteed,最不容易被赶;只设 requests 的是 Burstable;啥都没设的 BestEffort 第一个被牺牲。
Warning节点压力驱逐属于非自愿干扰,PDB(第 51 章)拦不住它,但它会占用 PDB 的预算额度。所以高可用既要 PDB,也要留冗余、设好资源请求。
52-7 故障恢复实战要点
把全书的自愈本领收成一张清单,排障时照着看:
- 副本少了不补 → 看 owner 控制器在不在、ReplicaSet 是不是被手动删了。
- 容器反复重启 →
kubectl describe pod看Last State、Restart Count,多半是 liveness 误杀或应用真崩。 - 流量打到坏实例 → 查 readiness 探针是否正确地把坏 Pod 摘出端点。
- 节点挂了服务断 → 确认
replicas ≥ 2且跨节点分布;单副本无解。 - 节点升级时被一波带走 → 用 PDB 限制同时下线数,让 drain 排队进行。
- 关键组件失联仍要活 → 考虑静态 Pod + 多控制平面节点。
Note自愈让”小故障自动消化”,但不能替代备份与容灾。数据库主从、跨可用区、定期备份,这些永远要单独设计。自愈管的是” Pod 和节点”这一层。
小结
Kubernetes 的自愈,是三层守护叠加的结果:
- 控制器调谐:让副本数永远向你写的期望靠拢。
- kubelet + 探针 + 重启策略:让单个容器崩了能拉起、卡死能重启、没好不透流量。
- 节点故障处理 + 调度:让节点没了副本能搬到别处。
记住一句总纲:冗余是自愈的前提,声明式是自愈的发动机。副本够多、期望写清,Kubernetes 就会日夜不停地帮你把系统修回正轨。
至此,本教程的”弹性与发布”部分(第 48–52 章)讲完。你已掌握从扩缩、发布到中断保护、自愈的完整韧性能力。