DB のバックアップと復元確認のスクリプトを追加(NAS の DSM タスクスケジューラ用)

This commit is contained in:
2026-10-04 16:03:54 +09:00
parent d4346c06fe
commit fb3e128757
6 changed files with 733 additions and 6 deletions
+91 -4
View File
@@ -56,7 +56,13 @@ tags:
/volume1/docker/tver-db/pgdata/
```
2. [[../deploy/nas/tver-db/compose.yaml|NAS用compose.yaml]] と `.env.example` を `/volume1/docker/tver-db/` に配置する。
2. [[../deploy/nas/tver-db/compose.yaml|NAS用compose.yaml]]、`.env.example`、`backup-db.sh`、`restore-test.sh`を`/volume1/docker/tver-db/`に配置し、スクリプトを所有者だけが実行できるようにする。
```bash
chmod 700 /volume1/docker/tver-db/backup-db.sh
chmod 700 /volume1/docker/tver-db/restore-test.sh
```
3. `.env.example`を`.env`へコピーし、`POSTGRES_PASSWORD`に十分長いランダムな値を設定する。値には、URLへの埋め込みで追加のエスケープが不要な16進文字列を使える。
```bash
@@ -232,7 +238,88 @@ git pull --ff-only
yt-dlpを更新するときは`Dockerfile.worker`の`YT_DLP_VERSION`の既定値を変更してリポジトリへ反映し、workerイメージをキャッシュなしで再ビルドする。更新後はworkerログと少数の実動画で抽出・保存を確認する。
## 5. 稼働後に残る作業
## 5. PostgreSQLをバックアップする
> [!todo] PostgreSQLバックアップ
> tver専用PostgreSQL 17コンテナ内の`pg_dump`で取得し、gzip圧縮してNASの`/volume1/backups/tver/`へ保存する日次処理を用意する。保持日数は既定14日とし、稼働確認後に別作業として実装する。
バックアップはNAS上のDSMタスクスケジューラから毎日実行する。`tver-postgres`コンテナ内の`pg_dump`を使って`/volume1/backups/tver/tver_<YYYYmmdd_HHMMSS>.sql.gz`へ保存し、既定では14日より古い世代を削除する。
> [!warning] バックアップ先も同じNASにある
> このバックアップはDBの誤操作や破損からの復元用であり、NAS本体の故障には備えられない。`/volume1/backups/tver/`はSynology Hyper Backupの対象にも含める。
### 5.1 DSMの日次タスクを登録する
DSMの「コントロール パネル」→「タスク スケジューラ」で「スケジュールされたタスク」→「ユーザー定義のスクリプト」を作成する。
| 設定 | 値 |
|---|---|
| ユーザー | `root` |
| 実行周期 | 毎日 |
| ユーザー定義のスクリプト | `bash /volume1/docker/tver-db/backup-db.sh` |
`DOCKER`、`CONTAINER`、`BACKUP_DIR`、`KEEP_DAYS`、`DB_USER`、`DB_NAME`は環境変数で上書きできる。通常運用では既定値を使う。
> [!todo] NAS実機で確認する
> DSMタスクの登録、1回の手動実行、日次実行の履歴、14日より古い世代の削除は未確認である。[要確認]
### 5.2 手動でバックアップを確認する
NASへSSH接続し、初回は手動で実行する。
```bash
bash /volume1/docker/tver-db/backup-db.sh
LATEST=$(find /volume1/backups/tver -name 'tver_*.sql.gz' -type f -print | sort | tail -n 1)
test -n "$LATEST"
test -s "$LATEST"
gzip -t "$LATEST"
ls -lh "$LATEST"
```
スクリプトが`OK:`、保存先、バイト数を表示し、`gzip -t`が成功することを確認する。`pg_dump`の失敗や空のダンプでは非0で終了し、完成ファイルを残さない。同じ秒の完成ファイルが既にある場合も非0で終了し、既存ファイルを上書きしない。同時実行時は同一ディレクトリ内のハードリンク作成に成功した一方だけが完成ファイルを公開する。
### 5.3 別DBへの復元を確認する
最新ダンプを本番DBへ戻す前に、同じコンテナ内の一時DB`tver_restore_test`へ復元する。
```bash
bash /volume1/docker/tver-db/restore-test.sh
tail -n 100 /volume1/backups/tver/restore-test.log
```
`download_jobs`、`subscriptions`、`known_episodes`、`schema_migrations`の行数が本番DBと一致し、最後に「復元確認に成功」と表示されることを確認する。復元SQLの通常出力は抑制され、ログには開始、各表の結果、成功または失敗が残る。SQLエラーは標準エラーとしてログに残る。一時DBは成功・失敗のどちらでもEXIT trapで削除される。本番DBに対しては行数取得の`SELECT`だけを実行する。
> [!todo] 復元確認を実行する
> 本物のNASと`tver-postgres`では未実行である。手動バックアップ後に`restore-test.sh`を1回実行し、ログと一時DBの削除を確認する。[要確認]
### 5.4 障害時に本番DBへ復元する
> [!danger] 本番DBを置き換える操作
> 先に[[#5.3 別DBへの復元を確認する]]を成功させ、復元対象のダンプを明示してから実行する。`tver`以外のDB名へ読み替えない。
1. dockageの`/opt/stacks/tver`でwebとworkerを停止し、DBへの書き込みを止める。
```bash
cd /opt/stacks/tver
docker compose stop web worker
```
2. NASで復元対象を指定し、存在・サイズ・gzip形式を確認する。
```bash
DUMP=/volume1/backups/tver/tver_<YYYYmmdd_HHMMSS>.sql.gz
test -s "$DUMP"
gzip -t "$DUMP"
```
3. NASで本番DBを作り直し、ダンプを復元する。
```bash
docker exec tver-postgres dropdb --if-exists -U tver tver
docker exec tver-postgres createdb -U tver tver
gzip -dc "$DUMP" | docker exec -i tver-postgres psql -v ON_ERROR_STOP=1 -U tver -d tver
```
4. dockageでwebとworkerを再開し、[[#3. 動作を確認する]]を実施する。
```bash
cd /opt/stacks/tver
docker compose start web worker
```