备份与恢复
控制平面的备份比大多数备份的任务更艰巨:它必须带着其可证明完好无损、篡改可检测的
账本回来。olivares dr 正是围绕这一要求构建的——每个捆绑包都记录每个租户的
链尖,恢复在所恢复的账本不具备连续性安全时以非零状态失败。dr drill
在临时目录里的合成账本上检查从备份到恢复的账本连续性,并打印测得的 RTO。
它不检查授权、密钥保管,也不检查恢复点之后的效果,并且不触及生产数据目录。
捆绑包在由你提供的 KEK 下加密——一个 Argon2id 派生的口令
(--passphrase-file)或一个来自你的 KMS 的原始 32 字节密钥
(--kek-key-file);二者必须且只能提供其一。审计与目录签名密钥以密封
形式随捆绑包一同传输。
26.10 中已登记的 DR 恢复控制支持 PostgreSQL 15、16、17 和 18(在 15.19、16.15、17.11 和 18.6 上测量)。其他主版本会被拒绝,并返回 DR restore control contract: PostgreSQL major <major> is unsupported (verified contracts: 15, 16, 17, 18),其中 <major> 是检测到的服务器主版本。控制绝不会被修复:在原地升级主版本后,若控制与新主版本的系统目录和权限不匹配,就会被拒绝。
SQLite(单节点)—— 在 serve 运行时也可安全执行(快照使用
VACUUM INTO;WAL 允许并发读取):
olivares dr backup \ --data-dir /var/lib/olivares --engine sqlite \ --out /backups/olivares-dr-$(date -u +%Y%m%dT%H%M%SZ).drbundle \ --passphrase-file <your-dr-passphrase-file>Postgres —— 由同一命令驱动的一致性 pg_dump --format=custom
(--engine postgres --dsn … --admin-dsn …),或用 --snapshot-file 把一个预制的
转储交给它。直接执行该转储必须提供 --admin-dsn:pg_dump 会保持
row_security=off,以应用角色去访问 FORCE ROW LEVEL SECURITY 的表时会中止,
因此该命令会在一开始就拒绝执行,而不是跑完却什么也没产出。
对于近乎零 RPO,--pitr-ref 会生成一个密钥+清单的配套捆绑包,与你的 WAL 归档
PITR 配置(deploy/postgres/backup/pitr-setup.md)配对使用;包装脚本
deploy/postgres/backup/pg-dump.sh / pg-restore.sh 封装了相同的流程。
两个值得了解的诚实开关:
- 备份在备份时拒绝捕获一个无法通过验证的账本——
--allow-unverified存在、 会被记录日志,且不推荐使用。 - 在使用预制快照(
--snapshot-file/--pitr-ref)且没有--admin-dsn(一个专用的NOSUPERUSER BYPASSRLS角色)时,备份会警告:所捕获的租户集合 可能受 RLS 限制而不完整——转储本身没有问题,需要该 admin 角色的是清单里的 跨租户清点。(直接执行pg_dump是另一种情况:会被直接拒绝,见上文。)
调度: Compose 栈提供了一个
备份 profile,
Helm chart 提供了一个
CronJob;
在裸机上,把上面的命令放进 cron。表中的数字是目标。对于 cron 分级,RPO
目标就是 cron 间隔。dr drill 在合成账本上测量 SQLite 的 RTO(恢复、启动
与校验)。它不测量 RPO,也不测量 Postgres 恢复。测得的 SQLite RTO 连同
事件数量和主机记在 docs/DR-RUNBOOK.md;它们不是本表中的目标。
| 分级 | 机制 | 目标 RPO | 目标 RTO |
|---|---|---|---|
| SQLite | cron 上的 dr backup |
cron 间隔 | < 15 分钟 |
| Postgres 逻辑备份 | cron 上的 pg-dump.sh |
cron 间隔 | < 30 分钟 |
| Postgres PITR | 基础备份 + WAL 归档 | ≈ 秒级 | < 30 分钟 |
把捆绑包镜像到异地,并把 KEK 与捆绑包分开存放(3-2-1):同主机备份 不是灾难恢复,而与口令一同传输的捆绑包在任何有意义的意义上都算不上加密。
演练——在你需要它之前
Section titled “演练——在你需要它之前”dr verify 在不触及你的数据目录的情况下检查捆绑包。对 SQLite,它在
临时目录中恢复并校验账本连续性,该检查失败时以非零状态退出。对 Postgres,
它检查捆绑包摘要以及密钥能否解密。Postgres 捆绑包的完整链校验需要恢复到
一个临时 Postgres。用下面的命令运行检查:
olivares dr verify --in /backups/olivares-dr-<ts>.drbundle \ --passphrase-file <your-dr-passphrase-file>dr inspect --in <bundle> 会打印清单(无需 KEK,不显示任何机密)——用的是哪个
引擎、哪些租户、哪些链尖。以与备份相同的节奏运行演练;一份未经验证的备份是一种
期望,而不是一项控制措施。
olivares dr restore --in /backups/olivares-dr-<ts>.drbundle \ --data-dir /var/lib/olivares --engine sqlite \ --passphrase-file <your-dr-passphrase-file>恢复顺序是刻意安排的:先是签名密钥(覆盖时失败关闭——--force 是显式的
覆盖手段),然后是存储快照,接着它会启动所恢复的存储并证明账本连续性,
若链不安全则以非零状态退出。任何恢复之后,都要针对你的离机检查点固定值
重新验证——一个恢复出来的较旧快照可能通过朴素的遍历,却在离机比对中失败
(故障排查 § 账本)。
决定一切的那两把密钥
Section titled “决定一切的那两把密钥”| 密钥 | 规则 |
|---|---|
| DR KEK(口令或原始密钥) | 没有它,每个捆绑包都只是噪声。把它存放在与捆绑包不同的系统中;同时丢失两者就是失效模式 |
audit-signing.key(在数据目录中) |
在置备时就把它离机备份——引擎仅在首次启动时警告,没有强制托管,丢失该密钥会使账本永久无法验证。也要把公钥离机固定(GET /v1/audit/pubkey) |
关于以 KMS 方式托管签名密钥本身(BYOK 信封、轮换仪式、olivares keys),见
CLI 参考;关于失效模式的逐步讲解,见
故障排查页。