给内测补上每日加密备份、宕机告警和日志上限。
主机安装和一次恢复演练留给产品。页面没有变化。 Co-Authored-By: Grok (agent loop)
This commit is contained in:
co-authored by
Grok (agent loop)
parent
71f7fac3a1
commit
53d8df257d
@@ -0,0 +1,63 @@
|
||||
# 生产备份恢复演练(2026-10-14)
|
||||
|
||||
给产品负责人照着做。这一次演练还原到一次性库,不碰正在服务的主库,网站不用停。真正整库还原会停写,放在文末,只有确认要覆盖现网数据时才做。
|
||||
|
||||
不要把备份文件、密钥、数据库口令、出生资料、姓名、邮箱或会话内容写进仓库、聊天或这份记录。
|
||||
|
||||
## 备份在哪里
|
||||
|
||||
- 每天北京时间 04:00,从 `main` 自动跑「Backup Production Daily」。也可以在 Gitea 里手动点一次。它只在 `main` 上跑。
|
||||
- 加密文件在生产主机 `/opt/jyotisha-production/backups/`,文件名是 `production-daily-日期T时间Z.dump.enc`。旁边有同名的 `-restore-verify.json`,里面只有行数和权限是否一致,没有用户正文。
|
||||
- 手动恢复点仍叫 `production-pre-migration-...`。每日清理只删过期的 `production-daily-` 文件,不会删手动恢复点。
|
||||
- Gitea 上的加密产物默认留 14 天。主机上的每日文件默认留 7 天。
|
||||
- 加密方式与现有恢复点相同:AES-256-CBC、PBKDF2。密钥在主机的数据库环境文件里,不要打印。
|
||||
|
||||
## 一次性库演练(不停机)
|
||||
|
||||
在生产主机上用 `deploy` 用户做。下面的库名换成当天的日期,不要用正在服务的那个库名。
|
||||
|
||||
1. 选定一个 `production-daily-*.dump.enc`。确认旁边的校验文件写着 `"ok": true` 和 `"restore_database_removed": true`。
|
||||
2. 进入 `/opt/jyotisha-production`。数据库口令和加密密钥已经在 `.env.production.database` 里。只在这台机器上读取,不要回显。
|
||||
3. 确认生产 Postgres 容器只有一个。容器名用 `docker ps` 看,下面记成 `<postgres>`。
|
||||
4. 建一次性库,名字必须不是主库名,例如 `restore_drill_20261015`:
|
||||
|
||||
```bash
|
||||
sudo -n docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" <postgres> \
|
||||
psql -U "$POSTGRES_USER" -d postgres -v ON_ERROR_STOP=1 \
|
||||
-c 'CREATE DATABASE "restore_drill_20261015";'
|
||||
```
|
||||
|
||||
5. 解密并还原进这个一次性库。不要把输出重定向到主库。
|
||||
|
||||
```bash
|
||||
openssl enc -d -aes-256-cbc -pbkdf2 \
|
||||
-pass env:PRODUCTION_BACKUP_ENCRYPTION_KEY \
|
||||
-in /opt/jyotisha-production/backups/production-daily-日期T时间Z.dump.enc |
|
||||
sudo -n docker exec -i -e PGPASSWORD="$POSTGRES_PASSWORD" <postgres> \
|
||||
pg_restore -U "$POSTGRES_USER" -d restore_drill_20261015 --exit-on-error
|
||||
```
|
||||
|
||||
6. 只记四个数字:`identity.users`、`public.profiles`、`public.credit_transactions`、`public` 里的表张数。不要把表里的内容抄出来。
|
||||
7. 删掉一次性库,并确认它已经不在:
|
||||
|
||||
```bash
|
||||
sudo -n docker exec -e PGPASSWORD="$POSTGRES_PASSWORD" <postgres> \
|
||||
psql -U "$POSTGRES_USER" -d postgres -v ON_ERROR_STOP=1 \
|
||||
-c 'DROP DATABASE "restore_drill_20261015" WITH (FORCE);'
|
||||
```
|
||||
|
||||
8. 把四个数字、文件名(不要附文件)、一次性库是否已删除,填进 `docs/testing/production-restore-drill-20261014.md`。
|
||||
|
||||
通过:还原命令退出码是 0,四个数字都是非负整数,一次性库已删除,主库没有被这条命令点名。
|
||||
|
||||
失败:停在失败的那一步。不要为了演练去改主库。把退出码交给验收,不要附带环境文件。
|
||||
|
||||
## 整库还原(会停机,平时不要做)
|
||||
|
||||
只有在确认现网库要被这份备份覆盖时才做。预留 30 分钟停写。这不是实测时间,数据变大就再加。
|
||||
|
||||
1. 停掉 `web` 和 `api`,让没有新的写入。Postgres 先留着。
|
||||
2. 用上面同一条解密和 `pg_restore`,目标改成主库名。这一步会覆盖主库里的现有数据。
|
||||
3. 核对四个行数,并对照校验文件里的权限三项是否为真。格式版本低于 2 的旧备份不要拿来做这件事。
|
||||
4. 再启动 `web` 和 `api`。打开 `https://jyotisha.chat/api/health`,`status` 应为 `ok`。
|
||||
5. 把实际停了多久填进演练模板。不要写用户内容。
|
||||
Reference in New Issue
Block a user