PostgreSQL復元実験:5件のデータと壊れたバックアップの記録
復元はコマンドの終了だけで合格にしない。元の内容と照合し、壊れた保存物が失敗として検知されるところまで試す。今回は架空の5件を使い、9項目を確認した。
2026年9月14日のローカル検証記録である。Docker Desktop上のPostgreSQL 18.6(Debian、aarch64)を使った。有料VPSには接続しておらず、実利用者のデータや稼働中のDBは扱っていない。
元のDBを残したまま、空の別DBへ戻した
新規コンテナ内にlab_source、lab_restored、失敗用のlab_badを作成した。ネットワークはnone、ホストへのポート公開はなし。1 CPU・512 MiBの上限を付けたが、この値は小さな実験を隔離するための設定で、運用に推奨するサーバー仕様ではない。
元データは次の5行だけだ。金額欄も試験用の整数であり、実際の取引ではない。
| id | label | amount |
|---|---|---|
| 1 | sample-a | 125 |
| 2 | sample-b | 250 |
| 3 | sample-c | 0 |
| 4 | sample-d | 875 |
| 5 | sample-e | 1000 |
主キー、labelの索引、amountを0以上に限定するCHECK制約、件数と合計を返すビューも用意した。単純な行コピーでは見落とす部分を照合するためだ。
pg_dump -Fcでカスタム形式を出力し、pg_restore --exit-on-error --single-transactionで空の復元先DBに読み込んだ。元DBの削除や上書きはしていない。
PostgreSQLのpg_restore資料では、既定はSQLエラー後も処理を続ける。今回はエラーで止め、全体を一つのトランザクションとして扱うオプションを付けた。巨大なDBにもこの設定が常に適切とは限らないので、対象の規模と版に合う復元計画が別途必要になる。
確かめた9項目
| 照合 | 観測した結果 |
|---|---|
| id順のCSV | 元と復元先がバイト単位で一致 |
| 復元したビュー | 5件、amount合計2250 |
| 索引 | 主キーとlabel索引の2本が存在 |
| CHECK制約 | amountが負の行の挿入を拒否 |
| 壊したアーカイブ | 先頭32バイトだけ渡すと終了コード1 |
| 失敗先DB | publicスキーマに表は作られていなかった |
| 元DB | 一連の操作後も同じCSVを返した |
| ダミー設定ファイル | tarから戻した内容が元と一致 |
| ダミー添付ファイル | tarから戻した内容が元と一致 |
壊したアーカイブではend of fileを含むエラーが出た。これはアーカイブ先頭の読み取り段階で失敗させたケースで、途中までSQLを実行した後のロールバックを実証したものではない。
ファイルの検証に使ったのは、試験用settings.jsonとattachment.txtの2点。稼働中のDBディレクトリをtarで固めた実験ではない。DBの整合性と、通常ファイルのコピー一致は分けて確認した。
小さな成功から分かる範囲
この実験では、ダンプが2,362バイト、取得が0.226秒、復元が0.205秒だった。新しいDBを準備する時間や障害を検知する時間は、この二つの処理時間に含まれない。ローカルの極小データなので、実サービスの復旧時間、VPS各社の速度、何GBなら何分という見積りには使えない。
クラスタ共通のロール、テーブルスペース、拡張機能、大規模データ、時点復旧、別ホストへの移行は未検証。n8nやDifyを起動して実業務が戻ることも確認していない。pg_dumpの対象は一つのDBであり、クラスタ全体の情報は別の扱いになる。
同じサンプルを手元で試す
実行スクリプト、今回のJSON記録、元のCSV、復元後のCSVを公開する。
Python 3.12以降とDockerを使い、新しい作業フォルダにスクリプトを保存する。先にdocker pull postgres:18でイメージを用意し、そのフォルダでpython3 run.pyを実行する。記録には実際に使った版とイメージの識別値が残る。タグの取得時期やCPU環境によって今回と同じ版にならない場合がある。
スクリプトは自分で新設した隔離コンテナだけを片付け、CSVやレポートを作業フォルダに残す。認証を省く設定は、ネットワークなし・ポート公開なしの架空データ実験に限定している。本番の接続先や鍵をこの例へ差し込む用途ではない。
自分の復元訓練に足すもの
次は「画面が開く」からもう一段先を確認する。試験環境で添付を開く、ログインする、外部へ送信しないサンプル処理を実行するなど、サービスごとの復旧条件を決める。
保存物の取得日時、許容するデータの欠損、担当者、検知から再開までの時刻、再開を承認した人を記録に残す。秘密情報が不足するなら、サーバーを大きくしても復元は進まない。
- 戻す対象を洗い出す: バックアップと復元のチェック表
- 停止の知らせを確かめる: 監視と通知のローカル実験
- 保守の担当を決め直す: マネージドと自己管理の境界
資料確認日: 2026年9月14日。実行時刻・全照合結果は上記JSON記録に収録している。