ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

CloudNativePG 恢复指南:基于物理备份的 Cluster 引导、PITR 与底层原理

CloudNativePG 恢复指南:基于物理备份的 Cluster 引导、PITR 与底层原理 CloudNativePG 恢复指南基于物理备份的 Cluster 引导、PITR 与底层原理【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pgCloudNativePGKubernetes Operator for PostgreSQL中的recovery恢复并非在已有集群上原地执行而是作为一种bootstrap引导模式从一个物理基础备份base backup启动一个全新集群并通过重放 WAL 日志把数据带到一致状态甚至精确恢复到任意时间点Point-In-Time RecoveryPITR。本文基于 docs/src/recovery.md 展开结合仓库源码api/v1/cluster_types.go、pkg/management/postgres/restore.go 等系统讲解三条恢复路径Barman Cloud 插件对象存储、VolumeSnapshot 卷快照、Backup 对象、PITR 全部恢复目标参数、恢复后应用数据库配置以及 operator 与实例管理器在底层是如何编排这一切的。读完本文你将能够独立编写bootstrap.recovery配置块、准确选择恢复目标并理解恢复过程中哪些操作被禁止、为什么。恢复Recovery在 CloudNativePG 中的定位PostgreSQL 的恢复系统本身稳健且功能丰富支持PITR——即把集群恢复到从最早可用备份到最新归档 WAL 之间的任意具体时刻。CloudNativePG 完整继承了这一能力但有一个关键的设计差异恢复不是在现有集群上原地执行而是用来引导bootstrap一个新集群。也就是说恢复是Cluster资源spec.bootstrap下的一个模式与 Bootstrap 文档中描述的其他引导方式如initdb、pg_basebackup平级。文档中的recoverybootstrap 模式允许你从一个物理基础备份初始化集群并重放关联的 WAL 文件使系统达到一致状态若配合recoveryTarget则可精确恢复到指定时间点。CloudNativePG 支持的恢复方式经历了演进当前版本聚焦于两条受支持的路径可插拔备份恢复接口CNPG-I——即 Barman Cloud Pluginbarman-cloud.cloudnative-pg.io用于从对象存储恢复从卷快照VolumeSnapshot原生恢复——依赖于底层 Kubernetes 存储基础设施的能力。需要特别说明的是自 1.26 版本起通过 Barman Cloud 从对象存储进行原生恢复已被废弃deprecated取而代之的是基于插件的方案。因此本文档不再介绍旧的原生 Barman Cloud 恢复遗留读者可参考 Appendix B – Recovery from an Object Store 的历史文档。无论采用哪种方式PITR 都强制要求存在一个有效的 WAL 归档WAL archive——这是执行时间点恢复的前提条件。从源码看恢复路径被抽象为两条执行分支。在 pkg/management/postgres/restore.go 的InitInfo.Restore方法中若集群配置了恢复源插件cluster.GetRecoverySourcePlugin()非空则走restoreViaPlugin否则走info.restoreViaBarmanObjectStore遗留的原生 Barman 路径。两条分支最终都会生成 PostgreSQL 配置与所需环境变量交给concludeRestore收尾。这印证了文档“插件路径为推荐方式、原生方式已废弃”的定位。从对象存储恢复使用 Barman Cloud Plugin前提条件对象存储中必须包含由 CloudNativePGCluster产生的备份数据——无论是通过已废弃的原生 Barman Cloud 集成还是通过Barman Cloud Plugin生成的。恢复时Barman Cloud Plugin 使用一个自定义的ObjectStore资源来描述承载基础备份与 WAL 文件的存储位置。第一步定义ObjectStore资源以下示例为 Azure Blob Storage 配置一个ObjectStoreapiVersion: barmancloud.cnpg.io/v1 kind: ObjectStore metadata: name: cluster-example-backup spec: configuration: destinationPath: https://STORAGEACCOUNTNAME.blob.core.windows.net/CONTAINERNAME/ azureCredentials: storageAccount: name: recovery-object-store-secret key: storage_account_name storageKey: name: recovery-object-store-secret key: storage_account_key wal: maxParallel: 8其中destinationPath指向对象存储中存放基础备份的容器azureCredentials引用承载存储账户名storageAccount与账户密钥storageKey的 Kubernetes Secretrecovery-object-store-secretwal.maxParallel: 8表示从归档并发下载 WAL 的并行度可显著加速恢复阶段的 WAL 拉取详见下文“如何加速恢复”。第二步配置Cluster的 recovery bootstrap在Cluster的bootstrap段指定恢复源并定义一个引用该插件的externalCluster条目apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-restore spec: [...] superuserSecret: name: superuser-secret bootstrap: recovery: source: origin externalClusters: - name: origin plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: cluster-example-backup serverName: cluster-example这里的关键字段bootstrap.recovery.source指定从哪个外部集群的备份进行恢复其值同时用作对象存储中的目录名因此必须设置为源集群的名称。这一点在 api/v1/cluster_types.go 的BootstrapRecovery.Source注释中明确写明“这也是备份存储的文件夹名称因此必须设为源集群的名字”。externalClusters[].plugin引用插件及其参数。barmanObjectName指向上面定义的ObjectStore资源名serverName是源集群在对象存储中使用的服务名。ExternalCluster与PluginConfiguration类型定义在 api/v1/cluster_types.go 与 api/v1/cluster_types.go 中其中plugin.name为必填plugin.parameters为键值对形式的自由参数。从VolumeSnapshot卷快照恢复CloudNativePG 允许从一个属于既有Cluster的 PVC 的VolumeSnapshot创建新集群。这些快照通过 volume snapshot backups 的声明式 API 创建。快照 外部 WAL 归档的组合恢复要完成恢复流程新集群还必须引用一个外部集群来提供 WAL 归档以便重放变更并最终完成恢复。下面的例子同时使用了VolumeSnapshot基础备份与通过 Barman Cloud Plugin 访问的 WAL 归档apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-restore spec: [...] bootstrap: recovery: source: origin volumeSnapshots: storage: name: snapshot name kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io externalClusters: - name: origin plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: cluster-example-backup serverName: cluster-examplevolumeSnapshots.storage使用标准的 KubernetesTypedLocalObjectReference见 api/v1/cluster_types.go 的DataSource类型指向承载 PGDATA 的快照。带独立 WAL 存储PGWAL的集群恢复如果被备份的集群使用独立的 PVC 存放 WAL 文件那么恢复时必须把walStorage的快照也带上apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-restore spec: [...] bootstrap: recovery: volumeSnapshots: storage: name: snapshot name kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io walStorage: name: snapshot name kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io注意DataSource结构体还预留了tablespaceStorage表空间存储映射当源集群使用了独立表空间卷时可一并指定。若恢复后的集群使用了与默认不同的应用数据库名/用户名必须在退出恢复阶段前配置好见后文“配置应用数据库”。从快照恢复副本集群的推荐做法如果要从快照引导一个 replica-mode副本模式集群并希望备用实例也充分利用快照而非仅主实例受益文档推荐以下三步流程先启动一个单实例副本集群——主实例使用快照恢复并利用源集群可用的 WAL对副本集群中的主实例再拍摄一个快照按需增加副本集群的实例数量。一个重要的性能警告当从VolumeSnapshot恢复主实例后创建副本时operator 可能回退到使用pg_basebackup来同步副本。对于大型数据库该过程可能显著变慢因为它涉及一次完整的基础备份。这一限制将在未来通过 scale-up 过程中对在线备份与 PVC 克隆的支持来解决。从源码看RestoreSnapshotpkg/management/postgres/restore.go负责快照恢复它会先清理 PGDATA 中的陈旧文件若存在恢复源则写入backup_label与表空间映射文件并通过插件或外部集群的 Barman 配置生成 WAL 恢复环境。而“快照不存在时回退到pg_basebackup”的逻辑可在 pkg/reconciler/persistentvolumeclaim/storagesource.go 附近看到——当引导用的 VolumeSnapshot 已不存在时副本创建会回退到pg_basebackup。从Backup对象恢复如果目标命名空间中已经存在一个Backup资源可以直接用.spec.bootstrap.recovery.backup.name指定其名称apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-example-initdb spec: instances: 3 bootstrap: recovery: backup: name: backup-example storage: size: 1Gi这种引导方式只需提供对所需恢复备份的引用。BackupSource类型api/v1/cluster_types.go除了内联的LocalObjectReference外还支持endpointCA字段——当使用自签名证书访问 Barman 端点时可在此挂载 CA 证书包避免证书签发者校验失败。需要说明的是bootstrap.recovery.backup与source、volumeSnapshots三者互斥见 api/v1/cluster_types.go 的字段注释一次恢复只能选择其中一种数据来源。恢复期间的通用限制Additional Considerations无论从对象存储、卷快照还是Backup资源恢复在Cluster完全提升为主实例并接受写操作之前不允许对数据库包括 catalog做任何更改。这一限制同样包含角色覆盖role overrides——它们会被推迟到集群转换为主实例之后。由此引出以下注意事项应用数据库名与用户恢复时会从被恢复的备份中拷贝应用数据库名称和用户。operator 目前不会备份底层的 Kubernetes Secret因为这是 Kubernetes 集群常规运维活动的一部分。保留原始 postgres 用户密码需要配置enableSuperuserAccess并提供superuserSecret。默认情况下恢复会沿默认目标时间线latest继续到最新可用的 WAL。你也可以通过recoveryTarget指定恢复目标执行 PITR见下一节。提速建议使用barmanObjectStore.wal.maxParallel选项可以加快从归档拉取 WAL——它通过并发下载事务日志来加速从恢复对象存储取回 WAL 的过程。这一机制在 pkg/management/postgres/restore.go 的setupBootstrapWALRestoreCache中得到体现恢复源的Wal配置预取并行度及额外的barman-cloud-wal-restore命令行参数会被写入本地缓存供wal-restore命令推导其选项与并行度。时间点恢复PITR核心概念与前提提取基础备份后与其重放全部 WAL 直到最新一条你可以让 PostgreSQL 在任意指定时刻停止重放——这就是 PostgreSQL 实现 PITR 的技术手段。WAL 归档的存在是强制性的并且必须通过 恢复目标 中描述的选项指定一个恢复目标。你只需在Cluster中指定恢复目标operator 就会自动生成该特性所需的全部 PostgreSQL 配置参数。这一说法有源码支撑api/v1/cluster_funcs.go 的RecoveryTarget.BuildPostgresOptions会把各个目标字段翻译成 PostgreSQL 的recovery_target_timeline、recovery_target_xid、recovery_target_name、recovery_target_lsn、recovery_target_time、recovery_target与recovery_target_inclusive等配置项。从对象存储执行 PITR以下示例沿用前面定义的 Azure 恢复对象存储同时包含基础备份与 WAL 归档恢复目标基于一个请求的时间戳apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-restore-pitr spec: instances: 3 storage: size: 5Gi bootstrap: recovery: # Recovery object store containing WAL archive and base backups source: origin recoveryTarget: # Time base target for the recovery targetTime: 2023-08-11 11:14:21.0000002 externalClusters: - name: origin plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: cluster-example-backup serverName: cluster-example这个例子只指定了targetTime时间戳形式不需要手动指定起始基础备份。基础备份的自动选择backupID选项用于指定发起恢复的基础备份默认值为空。一旦为其赋值Barman 备份 ID 形式operator 就会以该备份作为恢复基础——前提是你确认该备份存在且可访问。若不指定backupIDoperator 按如下规则自动检测基础备份使用targetTime或targetLSN时选择在该目标之前完成的最接近的备份其他情况下按时间顺序选择最后一个可用的备份。这一逻辑在 api/v1/cluster_types.go 的RecoveryTarget注释中有完整描述。从VolumeSnapshot对象执行 PITR下面的示例演示了“PGDATA 的VolumeSnapshot基础备份 对象存储中的 WAL 归档本例为 MinIOtargetTime恢复目标”的组合apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-example-snapshot spec: # ... bootstrap: recovery: source: origin volumeSnapshots: storage: name: test-snapshot-1 kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io recoveryTarget: targetTime: 2023-07-06T08:00:39Z externalClusters: - name: origin plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: minio-backup serverName: cluster-example这种配置使 CloudNativePG 从卷快照恢复基础数据再从对象存储应用 WAL 段最终达到指定的恢复目标。使用这一组合时请注意以下三条重要约束若被备份集群启用了walStorage还必须指定包含PGWAL目录的卷快照见上文“带独立 WAL 存储的集群恢复”你需要自行保证卷快照中基础备份的结束时间早于恢复目标时间戳若自上次基础备份以来你在集群中添加或移除了 tablespace重放 WAL 将会失败。你需要在表空间变更时刻与恢复目标时间戳之间制作一次基础备份。恢复目标Recovery targets你可以在recoveryTarget中使用以下目标判据targetTime: 恢复进行到的时间戳采用 RFC 3339 格式或 PostgreSQL 的 timestamp 格式。精确停止点还受exclusive选项影响。注意不带显式时区后缀的时间戳如2023-07-06 08:00:39一律按UTC解释。警告务必在时间戳中显式指定时区以避免歧义例如使用2023-07-06T08:00:39Z或2023-07-06T08:00:3902:00而不是2023-07-06 08:00:39。警告PostgreSQL 会在遇到指定时间之后的第一笔事务时停止恢复。如果目标时间之后不存在这样的事务恢复过程将失败。targetXID: 恢复进行到的事务 ID。精确停止点同样受exclusive选项影响。需要注意事务 ID 在事务开始时顺序分配但事务可能以不同的数字顺序完成。被恢复的是在该指定事务之前提交可选包含该事务本身的事务。targetName: 恢复进行到的命名恢复点restore point该恢复点通过pg_create_restore_point()预先创建。targetLSN: 恢复进行到的WAL 日志位置LSNLog Sequence Number。精确停止点受exclusive选项影响。targetImmediate: 一旦达到一致状态就结束恢复即尽可能早地结束。从在线备份恢复时这相当于备份结束的时刻。重要operator 只能在指定targetTime或targetLSN时自动检索最接近的备份对于其余目标targetName、targetXID、targetImmediate则无法做到此时必须显式指定backupID。基于targetName的示例apiVersion: postgresql.cnpg.io/v1 kind: Cluster [...] bootstrap: recovery: source: origin recoveryTarget: backupID: 20220616T142236 targetName: restore_point_1 [...]注意每个recoveryTarget配置中只能从这些目标里选择唯一一个targetTLI除外见下。目标时间线与包含/排他语义可以额外指定targetTLI强制恢复到特定时间线取值为latest或正整数。默认情况下上述参数被视为**包含性inclusive**的——在恢复目标之后立即停止这与 PostgreSQL 的recovery_target_inclusive默认行为一致。通过将exclusive设置为true可以请求排他性行为——在恢复目标之前立即停止。以下示例展示排他性恢复同时依赖 Azure 中的 blob 容器存放基础备份与 WAL 归档apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-restore-pitr spec: instances: 3 storage: size: 5Gi bootstrap: recovery: source: origin recoveryTarget: backupID: 20220616T142236 targetName: maintenance-activity exclusive: true externalClusters: - name: origin plugin: name: barman-cloud.cloudnative-pg.io parameters: barmanObjectName: cluster-example-backup serverName: cluster-exampleRecoveryTarget结构体中除上述字段外还包含TargetImmediate *bool与Exclusive *bool两个布尔指针字段api/v1/cluster_types.go。对应地api/v1/cluster_funcs.go 在targetImmediate为真时输出recovery_target immediate并根据exclusive输出recovery_target_inclusive false/true。配置应用数据库Configure the application database恢复后的集群可以额外配置应用数据库的名称与凭据。更新应用数据库凭据有两种方式一是自行生成密码、存放为 Secret 并让数据库引用它二是让 operator 生成一个带随机安全密码的 Secret。关于 Secret 的更多细节见 Bootstrap an empty cluster。重要当Cluster处于恢复模式时不允许对数据库包括 catalog做任何更改包括角色覆盖——它们会被推迟到集群转换为主实例之后。此阶段用户保持为源集群中的定义。以下示例在从活动集群引导后将app数据库配置为app用户所有密码取自 Secretapp-secretapiVersion: postgresql.cnpg.io/v1 kind: Cluster [...] spec: bootstrap: recovery: database: app owner: app secret: name: app-secret [...]上述配置下只有在恢复完成之后才会依次发生以下动作若app数据库不存在则创建它若app用户不存在则创建它若app用户不是app数据库的所有者则将所有权授予app用户若owner的值与 Secret 中的username值一致则应用用户此处即app的密码会被更新为 Secret 中的password值。源码层面ShouldRecoveryCreateApplicationDatabaseapi/v1/cluster_funcs.go决定恢复作业是否需要创建应用数据库仅当bootstrap.recovery存在、集群不是副本模式IsReplica()为假且同时指定了owner与database时才返回true。恢复流程在 pkg/management/postgres/restore.go 中据此设置ApplicationUser与ApplicationDatabase。恢复的底层工作原理编排流程对象存储中上传的数据可以被用来从一个既有备份引导一个新集群。operator 使用barman-cloud-restore工具恢复基础备份与barman-cloud-wal-restore工具恢复 WAL 文件支持按需启用并行编排整个恢复过程。recovery引导方式的详细说明参见 Bootstrap from a backup。整个恢复过程由运行在 Pod 内的**实例管理器instance manager**负责对用户完全透明。核心编排逻辑集中在 pkg/management/postgres/restore.goInitInfo.RestoreL272-L300恢复入口先加载Cluster再根据是否配置恢复源插件选择restoreViaPlugin或restoreViaBarmanObjectStore最后调用concludeRestore收尾restoreViaPluginL1135通过 CNPG-I 插件的postgres服务执行恢复如 Barman Cloud PluginrestoreViaBarmanObjectStoreL1179遗留的原生 Barman 恢复路径ensureArchiveContainsLastCheckpointRedoWALL302-L337在恢复前校验归档中是否存在从基础备份继续所需的首个 WAL 文件。具体的执行步骤可以概括为operator 在新集群的第一个实例中注入一个 init 容器该 init 容器开始从对象存储恢复基础备份基础备份复制到新 PVC 的耗时取决于备份的大小以及网络与存储的速度。基础备份恢复完成后operator 以恢复模式启动 PostgreSQL 实例。此阶段 PostgreSQL 已启动但不接受连接Pod 在 liveness 探针看来是健康的通过restore_commandPostgreSQL 开始从归档拉取 WAL 文件。可通过设置maxParallel并启用并行 WAL 恢复能力来加速此阶段当 PostgreSQL 到达目标时无论是最新 WAL 末尾还是 PITR 场景下的指定目标此阶段结束。若未指定recoveryTarget恢复默认沿latest时间线继续到最新可用 WAL恢复完成后operator 将所需的超级用户密码写入实例新的主实例照常启动其余实例作为副本加入集群。WAL 恢复的实现细节getRestoreWalConfigpkg/management/postgres/restore.go生成的 PostgreSQL 配置非常能说明问题restore_command被设置为/controller/manager wal-restore --log-destination ...——即 WAL 恢复委托给 operator 的wal-restore子命令执行与 HA 副本及 CNPG-I 插件恢复共用同一命令其实现见 internal/cmd/manager/walrestore/cmd.gorecovery_target_action被设置为promote确保达到恢复目标后自动提升为主实例。一个值得注意的安全设计是恢复源对象存储及其凭据永远不会出现在命令行中。它们通过本地 webserver 缓存setupBootstrapWALRestoreCachepkg/management/postgres/restore.go传递给wal-restore命令。在引导恢复作业期间实例管理器的常规缓存填充逻辑并未运行因此这里需要显式解析恢复源对于recovery.backup引用源存储信息只存在于被引用的BackupCR 中并将整个存储配置缓存起来使wal-restore命令能像在运行中的实例上一样推导其选项与预取并行度。配置建议如果你不熟悉 PostgreSQL PITR 的工作原理建议将恢复集群的.spec.postgresql.parameters配置为与原集群一致。待新集群恢复完成后再按需调整这些设置。恢复后立即接管备份带 Backup 段的恢复恢复集群时manifest 中可以包含指向backup对象存储资源的 Barman Cloud 插件plugins段。这使新创建的集群能够在恢复后立即开始归档 WAL 并执行备份——前提是配置了备份策略。# 示意恢复集群同时配置恢复源与备份目标 apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: cluster-restore spec: # ...恢复配置bootstrap.recovery externalClusters... backup: # 指向备份专用 ObjectStore 的插件配置 ...这里有两个关键的运维准则避免在同一集群中为 backup 与 recovery 复用同一个ObjectStore配置。如果必须复用请确保每个集群使用唯一的serverName防止意外覆盖备份或 WAL 归档数据。CloudNativePG 内置了安全检查防止集群覆盖共享存储桶中的既有数据。若检测到冲突集群会停留在Setting up primary状态相关 Pod 以错误失败Pod 日志显示ERROR: WAL archive check failed for server recoveredCluster: Expected empty archive绕过安全检查的例外可以通过在恢复的集群上设置cnpg.io/skipEmptyWalArchiveCheck注解为enabled来绕过此检查。但强烈不建议这样做除非你对 PostgreSQL 的恢复流程非常熟悉——错误地跳过检查可能导致严重的数据丢失。请仅在专家场景下谨慎使用。小结CloudNativePG 将 PostgreSQL 的物理备份恢复能力封装为bootstrap.recovery引导模式支持三条路径Barman Cloud 插件从对象存储恢复推荐原生 Barman 自 1.26 起废弃、从VolumeSnapshot原生恢复、以及直接引用现有Backup对象恢复。PITR 依赖 WAL 归档与recoveryTarget支持targetTime、targetXID、targetName、targetLSN、targetImmediate五类目标每次只能选其一并可配合targetTLI与exclusive控制时间线与包含语义。恢复完成后才会创建或更新应用数据库及其所有者与密码恢复期间对数据库的任何写操作与角色覆盖都会被禁止或推迟。整个流程由 operator 注入 init 容器、实例管理器与wal-restore子命令透明编排所有恢复目标的参数均由 operator 自动转换为 PostgreSQL 的recovery_target_*配置项。如需进一步深入可继续阅读Bootstrap、backup_recovery、backup、volume snapshot backups、tablespaces以及示例文件 cluster-example-bis-restore.yaml 与 cluster-example-replica-from-backup-simple.yaml。【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表