disaster-recovery

Kubernetes集群灾难恢复方法论:RTO/RPO、备份分层、演练与跨区域切换

补充说明

灾难恢复(Disaster Recovery,DR) 回答的不是「怎么备份」,而是「出事之后多久能恢复、能丢多少数据、谁来决定切换」。备份只是 DR 的一个输入 —— 有备份但没有恢复流程、没有演练记录、没有决策人,等于没有 DR。

一个常见的误解是把 DR 当成「运维的事」。实际上 DR 是业务连续性的一部分:业务方定义 RTO/RPO,运维实现它,双方一起验收。技术手段只是最后一步。

RTO 与 RPO

两个指标决定了整套架构的成本,必须在动手之前先定下来:

RTO(Recovery Time Objective)  恢复时间目标 —— 业务能容忍中断多久
RPO(Recovery Point Objective) 恢复点目标 —— 业务能容忍丢多少数据

例:
  内部工具      RTO 24h / RPO 24h   每天一次备份足矣
  一般业务系统  RTO 4h  / RPO 1h    定时备份 + 自动化恢复脚本
  核心交易      RTO 15m / RPO 0     需要同步复制 + 多活,成本指数级上升

关键约束:RPO 越接近 0,成本越接近无穷。RPO=0 意味着同步复制,而跨可用区的同步复制受物理延迟限制(同城两中心往返通常 1-3 ms,跨城 30 ms 以上),跨区域做到 RPO=0 在工程上基本不成立。

灾难分级与对应的恢复手段

不同级别的故障,恢复手段完全不同。「灾难恢复」这个词通常只指第 4 级及以下:

1. 单 Pod 故障         kubelet/Deployment 自动重建,不需要 DR
2. 单节点故障          工作负载自动漂移,不需要 DR(要保证副本数与 PDB)
3. 命名空间/资源误删    从备份恢复该命名空间,分钟级
4. 控制面损坏          etcd 快照恢复,或重建控制面,小时级
5. 整个集群/区域故障    从备份在新集群重建,或切换到异地集群,小时到天级
6. 数据被污染/加密     需要多版本备份 + 不可变存储,能回到污染前的时间点

第 6 级最容易被低估:勒索软件不会立刻发作,它先潜伏数周把备份一起加密。这时候「只保留最近一份备份」的策略是致命的。

备份对象的分层

集群里需要保护的东西远不止 etcd。分层看:

L1 声明层    Deployment/Service/ConfigMap/Secret/CRD/CR 等 API 对象
L2 数据层    PersistentVolume 里的实际数据
L3 控制面    etcd 数据、控制面证书与密钥、加密配置
L4 集群外    镜像仓库、DNS 记录、负载均衡配置、IaC 代码、CI/CD 流水线
L5 凭据      对象存储 AK/SK、云厂商账号、备份加密密钥、kubeconfig

绝大多数「恢复失败」的案例,问题出在 L4 和 L5:集群恢复出来了,但镜像仓库没同步、DNS 没切、备份存储的密钥在离职同事的密码管理器里。

三种恢复形态

形态 做法 典型 RTO 成本
冷备(Backup & Restore) 备份放对象存储,出事时新建集群恢复 数小时到数天 低
温备(Pilot Light) 异地常驻最小集群,出事时扩容 30 分钟到数小时 中
多活(Active-Active) 多集群同时承载流量 接近 0 高

冷备的 RTO 里,新建集群 + 拉起控制面 + 恢复声明 + 恢复数据 + 改 DNS 每一步都要算时间。很多团队估的 RTO 只算了 velero restore 那一步,真实耗时是它的 5-10 倍。

跨区域切换要解决的问题

跨区域切换不只是「把流量切过去」,至少要覆盖:

1. 镜像    目标区域仓库里有同版本镜像(建议做镜像同步,而不是切过去再拉)
2. 声明    集群资源能在目标集群重建(注意 StorageClass/IngressClass 名字差异)
3. 数据    状态化服务的数据如何过去(存储层复制 / 应用级复制)
4. 证书    TLS 证书、ServiceAccount 密钥、webhook CA 是否在目标可用
5. 网络    Service CIDR、Pod CIDR 不能与本区域其他网络冲突
6. 流量    DNS TTL 要提前调小,否则切了也要等 TTL 到期
7. 回切    切换失败怎么切回来,回切时原区域的数据是否已经落后

DNS 的 TTL 是一个具体的坑:平时把 TTL 设成 3600 秒,出事时切换要等一小时才全量生效。做 DR 的域名 TTL 应在切换前至少一天调到 60 秒。

用 Velero 做一次最小可用的恢复

以一个命名空间级恢复为例,完整链路是:

# 1. 异地集群上先装好 Velero,并指向同一个备份存储位置
velero backup-location get

# 2. 确认备份存在且状态为 Completed
velero backup get
velero backup describe dev-backup --details

# 3. 恢复到新集群(排除节点、事件等集群相关对象)
velero restore create --from-backup dev-backup \
  --exclude-resources nodes,events,events.events.k8s.io \
  --namespace-mappings dev:dev

# 4. 盯住恢复过程,重点看 PartiallyFailed
velero restore get
velero restore describe dev-backup-20260918020000
velero restore logs dev-backup-20260918020000

Velero 负责 L1;L2 要看卷数据是否随备份一起走了(见 cluster-backup),L3 要用 etcd 快照单独恢复。

恢复演练

演练是 DR 里唯一不能被省略的环节。 做法:

1. 隔离环境      新建一个独立集群/命名空间,绝不直接在生产的备份上试
2. 定期执行      核心业务每季度一次,一般业务每半年一次
3. 记录耗时      从「决定恢复」到「业务可用」的真实分钟数,而不是命令执行时间
4. 验收标准      由业务方定义:能登录、能下单、数据条数对得上
5. 演练后修正    把演练中踩的坑写回文档,更新 RTO 估算

演练要真的跑过一遍。只在文档里写了步骤、没实际执行过的恢复流程,第一次执行时几乎一定会在某个环节卡住 —— 通常是证书、权限或某个被忘掉的依赖。

恢复优先级的排序原则

灾难现场最忌讳「按清单从上往下恢复」。正确的顺序由依赖关系决定,而不是由重要性决定:

1. 控制面            apiserver / etcd / 控制器可用,否则一切操作都无从谈起
2. 基础依赖          CNI、CSI、DNS、证书签发、镜像仓库可达
3. 身份与密钥        Namespace、ServiceAccount、Secret、RBAC
4. 数据层            数据库、消息队列、存储,先于依赖它的业务
5. 无状态业务        前端、API 层
6. 入口与策略        Ingress/Gateway、NetworkPolicy、准入 Webhook
7. 观测与审计        监控、日志,最后恢复即可

把第 7 步放在最后是有意的:监控很重要,但它在恢复过程中不产生业务价值,却常常因为「先恢复监控才能看到进展」的心理被优先处理,白白消耗宝贵的恢复窗口。恢复期间应直接看组件日志与命令行探测结果。

场景化处置

三个最常见的场景,处置路径差别很大:

场景一:误删命名空间
  影响面    单个或几个命名空间
  处置      不要尝试手工重建资源,直接从最近一次备份恢复该命名空间
  注意      恢复前先确认「误删之后是否已经有新对象写入同名命名空间」,
            否则会出现新旧对象混在一起;必要时先恢复到一个临时命名空间做比对

场景二:etcd 损坏或数据被污染
  影响面    整个控制面,所有 API 对象
  处置      停 apiserver 与 etcd → 用最近一份可用快照恢复 → 校准证书与 sa.key
  注意      恢复到哪个时间点需要业务判断:恢复得太早会丢最近的操作,
            恢复得太晚可能把污染一起带回来;快照必须先做完整性校验再使用

场景三:区域不可用
  影响面    整个集群或大部分节点
  处置      在备用区域新建/扩容集群 → 恢复声明与数据 → 调小过的 DNS TTL 生效
  注意      数据能否追上取决于复制方式,异步复制必然有 RPO;
            切过去之前要确认目标区域有足够的配额与镜像

三种场景的共同点是:真正的恢复动作只占全部工作量的一小部分,剩下的是判断、验证与切换协调。

注意

  1. 只备份 etcd 而不备份 PV 数据等于没备份。etcd 快照里只有「PV 应该存在」的声明,没有 PV 里的字节。恢复出来的 PVC 会绑定到空的卷上,Pod 能启动但读不到数据。etcd 快照与卷数据备份必须成对存在。
  2. 备份不等于可恢复,恢复演练必须真的在隔离环境跑过。备份任务的「成功」只说明数据上传完成,不说明恢复链路可用 —— 权限、存储类、CRD 版本、网络策略都可能在恢复时才暴露问题。
  3. 恢复顺序有依赖:先 CRD 再 CR,先 Namespace 再其中的资源,先 webhook 后端再启用 webhook 配置。顺序错了会出现「资源被 apiserver 直接丢弃」或「恢复过程被自己的准入 webhook 拦截」。
  4. ServiceAccount 与证书在恢复后可能失效。控制面的 sa.key/sa.pub 决定 SA token 能否被验证,集群 CA 决定 kubelet 客户端证书是否被接受。跨集群恢复时如果 CA 不同,原节点的证书全部作废,必须重新签发。
  5. 跨版本恢复不保证兼容。把 1.34 的备份恢复到 1.29 会因为对象字段、CRD schema 版本被 apiserver 拒绝;etcd 快照更是只能在同版本上恢复(etcd 3.5 无法读取 3.6 写出的数据)。先确认目标集群版本,再决定恢复路径。
  6. 存储快照不是备份。CSI VolumeSnapshot 通常与原卷在同一存储系统、同一账号下,误删 PV、误删存储池或账号被盗时快照会一起消失。快照适合快速回滚,异地副本才叫备份。
  7. 备份存储的凭据本身也是单点。对象存储的 AK/SK、加密密钥、kubeconfig 需要异地保存并纳入密钥管理,否则集群没了的同时备份也打不开。
  8. 别把 RTO 估算成一个命令的时间。新建集群、装 CNI/CSI、拉镜像、恢复声明、恢复数据、切 DNS,每一段都要计时;镜像没预热时,拉取时间往往是大头。
  9. DNS TTL 平时就要调小。等出事当天才想起来改 TTL,切换会被 TTL 拖住几十分钟。
  10. 备份系统需要被监控。「备份任务连续失败三天没人发现」是最常见的事故前兆 —— 对备份时间戳做告警(见 backup-strategy),而不是只看任务是否退出码为 0。
  11. DR 是组织问题,不只是技术问题。谁有权决定切换、切换后谁来验证、多久没演练算失效 —— 这些没有答案时,技术再完备也切不动。

相关主题

参考链接