PostgreSQL 磁盘故障恢复:用 CloudNative-PG Volume Snapshot 分钟级重建集群
【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg
凌晨两点,值班手机响了:生产 Kubernetes 集群上某台节点磁盘报错,CloudNative-PG 管理的 PostgreSQL 集群 Pod 全部 CrashLoopBackOff,PVC 挂载失败,应用报连接超时。业务方只问一句——数据什么时候能回来。这篇文章讲的就是这个场景下,如何基于 CloudNative-PG 的恢复机制,用最小的人工操作把整个 PostgreSQL 集群重建出来。读完你会带走三样东西:判断该走哪条恢复路径的决策逻辑、一份能直接改参数就用的恢复配置,以及一套验证数据完整性的检查清单。
动手前先诊断:三个问题决定你走哪条路
别急着写 YAML。先花五分钟回答三个问题,路径自然就出来了:
- 你的 StorageClass 支持 Volume Snapshot(Kubernetes 的卷快照 API,由底层 CSI 存储驱动提供)吗?有没有近期快照?支持、且快照时间接近故障点,就走快照恢复——恢复时间与数据库大小基本无关,这是首选。
- WAL 归档(预写日志归档,PostgreSQL 记录每次变更的日志流)还在吗、可访问吗?CloudNative-PG 的恢复不是原地修复,而是用「基础备份 + 回放 WAL」的方式引导出一个新集群。快照恢复和对象存储恢复都依赖一个可达的 WAL 归档来补齐一致性,PITR(按时间点恢复)更是必须。归档丢了,恢复点就只能退回最近的快照/备份时刻。
- 目标是「回到故障前」还是「停回某个时刻」?比如要回滚一笔坏交易,就在恢复配置里加一个
recoveryTarget,不需要换路径。
⚠️ 判断顺序上,第 2 个问题是一票否决项:没有可用的 WAL 归档,先想办法保住归档,再谈恢复路径。
从 VolumeSnapshot 重建集群:定位快照、声明新集群、等待提升
快照恢复的核心逻辑一句话:用存储层做过的块级快照快速铺出新集群的数据盘,再用对象存储里的 WAL 回放把数据推到一致状态。因为快照是存储层增量做的,数据量从 100GB 涨到 1TB,恢复时间基本不增长,网络也不需要搬运备份文件——这就是它成为首选的原因。
前提:快照备份和 WAL 归档已经配好
这是平时就要做的事,不是事故现场才做。在集群声明里开启卷快照备份,同时让 Barman Cloud 插件承担 WAL 归档,配置长这样:
apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: pg-production spec: instances: 3 storage: storageClass: gp3 size: 10Gi walStorage: storageClass: gp3 size: 10Gi backup: volumeSnapshot: className: gp3-vsc plugins: - name: barman-cloud.cloudnative-pg.io isWALArchiver: true parameters: barmanObjectName: production-backup-store字段含义和全部可选项见 docs/src/appendixes/backup_volumesnapshot.md,WAL 归档的细节见 docs/src/wal_archiving.md。
找到最近的那份快照
确认 CSI 驱动支持快照后,快照会以 Kubernetes 的VolumeSnapshot资源存在,带着集群标签:
kubectl get volumesnapshot -l cnpg.io/cluster=pg-production -o wide选时间戳最接近故障点、状态为 Ready 的那一份,记下名字。如果集群的 WAL 放在独立卷上(上面配置的walStorage),同样要找到它的快照,恢复时两者都要带上。
声明恢复集群
新集群用bootstrap.recovery引导:source指向原集群名,volumeSnapshots指定数据盘快照,externalClusters通过 Barman Cloud 插件挂上 WAL 归档。注意新集群名字要换一个,别和还在现场的原集群撞名:
apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: pg-production-restored spec: instances: 1 bootstrap: recovery: source: pg-production volumeSnapshots: storage: name: <pgdata 快照名> kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io walStorage: name: <wal 快照名> kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io externalClusters: - name: pg-production plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: production-backup-store serverName: pg-productionserverName必须等于源集群名——它在对象存储里就是备份的存放目录名。WAL 回放完成后,新集群会自动提升为主节点。
盯着它到 Ready
kubectl get cluster pg-production-restored -w kubectl describe cluster pg-production-restored关注 conditions 里的恢复进展:快照卷挂载、WAL 回放、提升为主。Pod 日志可以用kubectl logs -f pg-production-restored-1 -c postgres跟踪。确认状态健康后,把应用的数据源切到新集群(或直接把 Service 指过去),然后按下一节的清单验收。
如果快照这条路走不通,还有两个备选
如果你的 StorageClass 不支持快照,或者事故窗口里快照已经过期太久,就走对象存储恢复:备份由 Barman Cloud 插件从对象存储(S3、Azure Blob 等)拉取,先用一个ObjectStore资源(barmancloud.cnpg.io/v1)声明备份桶的位置和凭证,再在bootstrap.recovery里只写source加插件引用即可。注意 1.26 版本起,内置的 Barman Cloud 集成已废弃,推荐统一走插件方式,完整流程在 docs/src/recovery.md。
如果需要精确停回某个时刻(而不是故障前最新状态),无论走哪条路径,在bootstrap.recovery里加一个recoveryTarget即可:
bootstrap: recovery: source: pg-production recoveryTarget: targetTime: "2026-09-17T02:15:00Z" exclusive: true另外,同命名空间里如果已经存在Backup资源,还可以用bootstrap.recovery.backup.name直接按名字引用它恢复,适合恢复演练时复用历史备份。
恢复完成不等于恢复成功:验收清单
集群显示健康之后,逐项过一遍再宣布事故结束:
- 集群 conditions 显示已提升为主,
status.phase正常 SELECT COUNT(*)核对关键表行数,与故障前记录一致SELECT MAX(created_at)对照事故时间线,确认恢复点符合预期(PITR 场景重点查这一项)- 应用库和应用用户存在且可登录(默认库名是
app,源集群若用了别的名字,恢复前要在配置里显式指定database/owner) - WAL 归档在新集群上已重新跑起来——这是下一次事故的救命绳
- 应用侧做一轮真实的读写冒烟,确认连接池、DNS/Service 指向都对
最容易踩的四个坑:现象、根因、对策
- 恢复 Pod 卡在 Init 容器—— 快照卷没挂上,或 Pod 访问不到 WAL 归档。对策:检查
VolumeSnapshotClass与 StorageClass 是否匹配、对象存储的网络和凭证是否可达。 - 恢复后加副本很慢—— 从快照恢复主节点后,操作符同步新副本时会退回
pg_basebackup做全量基础备份,库越大越慢。对策:先以单实例恢复,等它 Ready 后对主节点再打一份快照,然后扩副本,快照会直接铺给新实例。 - 恢复中途想改数据改不了—— 集群处于恢复态,在提升为主之前对数据库和系统目录的任何修改(包括角色覆盖)都会被推迟。对策:等提升完成后再动,不要和恢复流程抢操作。
- PITR 回放慢—— 瓶颈是待回放的 WAL 数量,不是快照。对策:调大对象存储 WAL 配置里的
maxParallel并发(ObjectStore资源的wal.maxParallel字段)。
这周就做一件事:验证你的快照和归档真的能用
恢复能力不是事故当天验证的。本周做两件事:确认生产集群的backup.volumeSnapshot和 WAL 归档都已启用且最近一次备份成功;挑一个低峰窗口,用最近一份快照真实地恢复一次演练集群,把本文的验收清单跑完。演练跑通了,下一次磁盘故障就只是重复流程。
下一步想深入,建议读 docs/src/recovery.md(三种恢复方式的完整说明)和 docs/src/bootstrap.md(bootstrap段落的全部字段)。下一篇我们聊跨集群场景:怎么用副本集群把 PostgreSQL 从一套 Kubernetes 集群迁到另一套。
【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考