バックアップして終わりにしない――セルフホスト環境の復元テスト入門
2026-07-12
バックアップして終わりにしない――セルフホスト環境の復元テスト入門のカバー画像

セルフホストのバックアップは、PersistentVolumeをコピーすれば終わりではありません。アプリによってはDB、画像などの実ファイル、設定、Secretが別々にあり、正しい順番で戻さないと起動してもデータが見えないことがあります。

私も、PV、DB dump、Git上の設定を個別に保存するだけでは、復旧手順が完成していないと感じるようになりました。大切なのは「何を保存したか」より、新しい環境へ何から戻し、どこまで確認すれば復旧完了なのかを決めることです。

この記事では、個別製品の現在の配置やバックアップ先には触れず、セルフホスト全体に使える復旧設計、RPO・RTO、棚卸し表、復元テストの進め方をまとめます。

記事確認日: 2026年7月12日

先に結論

私がセルフホスト環境のバックアップを考えるときは、対象を次の6つに分けます。

  1. クラスタやサーバーを再構築するための情報
  2. Kubernetes manifestやアプリ設定
  3. Secret、暗号化鍵、証明書に関する復旧手段
  4. PostgreSQLなどのDB
  5. 写真、添付ファイル、リポジトリなどの実ファイル
  6. バージョンと復旧順序を記録した手順書

そして、復旧時はおおむね次の順で戻します。

サーバー・クラスタ
  ↓
ストレージとSecret管理の土台
  ↓
CRD・Operator・共通基盤
  ↓
アプリのmanifestとSecret
  ↓
DB
  ↓
実ファイル
  ↓
アプリ起動・migration
  ↓
ログイン、検索、アップロードなどの動作確認

この順番はアプリによって変わります。重要なのは、バックアップ処理を作る前に、復旧の依存関係を一度書き出すことです。

PVを保存しただけでは足りない理由

KubernetesのPVは、アプリから見える永続ストレージです。しかし、PVの中身がアプリの全データとは限りません。

例えば、一般的なWebアプリには次のようなデータがあります。

データ 保存される場所の例 PVだけで戻るか
ユーザー、記事、設定値 PostgreSQLやMariaDB DBの保存方法による
画像、動画、添付ファイル ファイル用PVやオブジェクトストレージ 対象PVだけでは不足する場合がある
検索インデックス、キャッシュ 別PVまたは一時領域 再生成できる場合が多い
アプリ設定 Git、ConfigMap、環境変数 PVとは別に必要
認証情報、暗号化鍵 Secret管理基盤など PVとは別に必要
アプリとDBのバージョン image tag、Helm values、手順書 PVには入っていない

PVのコピーが成功しても、DBと実ファイルの時点がずれていれば、DBには存在するのにファイルがない、またはその逆が起きます。アプリが提供するmaintenance modeやバックアップ手順がある場合は、それを優先します。

スナップショットとバックアップを分ける

スナップショットは、障害前へ素早く戻るために便利です。ただし、同じストレージシステム内だけにあるスナップショットは、そのストレージ全体を失う障害へのオフサイトバックアップにはなりません。

KubernetesのVolumeSnapshotは、CSIドライバーを通じてストレージシステム上のvolumeを特定時点で取得する仕組みです。利用できるか、どこに保存されるか、復元方法はCSIドライバーに依存します。KubernetesのVolumeSnapshot公式説明では、CSIドライバー側の対応が必要で、削除時の扱いはDeletionPolicyにも左右されると説明されています。

分散ストレージ製品でも、クラスタ内のsnapshotとremote backupは分けて考えます。例えばLonghornは、snapshotに加えてremote backup targetへのbackupとrestoreを提供しています。具体的な操作はバージョンで変わるため、LonghornのBackup and Restore公式手順を確認してください。

私の場合は、次の役割分担で考えると整理しやすくなりました。

  • snapshot: 更新前の短期的な切り戻し
  • remote backup: ノードやクラスタ全体を失った場合の復旧
  • DB dump: DBを別環境へ論理的に戻す手段
  • ファイルのオフサイトコピー: 写真や添付ファイルなどを別の障害領域へ逃がす

どれか1つを万能なバックアップとして扱わず、障害の種類ごとに使い分けます。

local PVはノード障害を先に考える

local PVやhostPathを使う構成では、データが特定ノードのディスクにあります。manifestをGitへ保存しても、ディスク上の実データはGitには入りません。

この構成で先に確認するのは、次の点です。

  • どのデータがノードローカルか
  • ノードが起動しない場合に、ディスクまたはバックアップから取り出せるか
  • 新しいノードのどこへ戻すか
  • PVとPVCを再作成する手順があるか
  • 所有者、グループ、パーミッションを再現できるか
  • node affinityなど、配置条件を新環境に合わせて変更できるか

PVのpersistentVolumeReclaimPolicyRetainにすると、PVCを削除してもPVとデータを残せます。ただし、これは誤削除時の安全策であって、ディスク故障やノード消失に備える別コピーではありません。挙動はKubernetesのPersistentVolume公式説明で確認できます。

DBはファイルコピーではなく論理dumpを用意する

PostgreSQLを例にすると、稼働中のDBデータディレクトリを単純にファイルコピーするより、pg_dumpやDBが推奨するバックアップ方式を使う方が復元手順を明確にできます。

PostgreSQL公式ドキュメントによると、pg_dumpはDBが利用中でも一貫したexportを作成できます。1つのDBを対象とし、roleやtablespaceなどクラスタ全体の情報は別途考える必要があります。custom formatはpg_restoreで選択的に復元でき、圧縮も行われます。

基本形は次のようになります。

pg_dump --host db.example.invalid --username backup_user \
  -Fc --file appdb.dump appdb

.invalidは実在しないことが保証された例示用ドメインです。接続先、ユーザー名、DB名は自分の環境へ置き換え、パスワードは環境変数や安全な認証方法で渡します。コマンド履歴や記事へ直接書きません。

復元テストでは、稼働中のDBへ上書きせず、使い捨ての検証用DBへ戻します。

createdb --host restore-db.example.invalid --username restore_user \
  appdb_restore_test
pg_restore --host restore-db.example.invalid --username restore_user \
  --dbname appdb_restore_test appdb.dump

その後、代表的なテーブル、レコード数、文字化け、拡張機能、アプリからの接続を確認します。dumpとrestoreに使うクライアント・サーバーのmajor versionにも互換性の条件があるため、公開時や復元時はPostgreSQLのpg_dumppg_restoreを確認してください。

DB dumpが作成できたことと、アプリがそのDBを使って起動できることは別です。復元後にmigrationが必要な場合もあるため、アプリとDBのバージョンを一緒に記録します。

また、pg_dumpだけで任意時点へ戻すPITRができるわけではありません。更新量が多い環境や厳しいRPOが必要な環境では、WAL archiveや物理backupを含むPostgreSQL公式のbackup方針を検討します。

実ファイルはDBと近い時点で保存する

写真管理、ファイル共有、CMSなどでは、DBにメタデータがあり、実体は別のファイル領域にあることがあります。

例えば、次の順番を決めます。

  1. 新しい書き込みを止める、またはmaintenance modeへ入れる
  2. DB dumpを取得する
  3. 実ファイルをsnapshotまたは別領域へコピーする
  4. 件数やハッシュを確認する
  5. 書き込みを再開する

停止できない場合は、どの時点まで戻せるかを明記します。DB dumpと実ファイルの時刻差が大きいほど、復元後に不整合が発生しやすくなります。

オフサイトコピーの具体例は、rcloneでpCloudへバックアップし、復元テストまで行う方法に分けて書いています。

設定はGitにあっても、再構築できるとは限らない

Kubernetes manifestをGitで管理すると、Deployment、Service、PVCなどを再作成しやすくなります。しかし、GitにYAMLがあるだけでは、同じ環境を再現できない場合があります。

一緒に確認したいものは次の通りです。

  • Kubernetesとk3sのバージョン
  • Helm chartとコンテナイメージのバージョン
  • CRDとOperatorを適用する順序
  • StorageClass、VolumeSnapshotClass、reclaim policy
  • 外部サービスとの依存関係
  • DNSや証明書を切り替えるタイミング
  • Git自体が利用できない場合のbootstrap手順

GitサーバーやGitOpsコントローラーが復旧対象のクラスタ内にある場合は、循環依存が生まれます。クラスタが空でも最初のmanifestを取得できる、独立したコピーまたはbootstrap手順を用意します。

Secretと鍵は「値」より復旧方法を管理する

Secretは、通常のmanifestと同じ場所へ平文で置くべきではありません。一方、Secret管理基盤を導入しても、その基盤自体の復旧情報を失えばアプリを戻せません。

方式ごとに、失うと復元できなくなるものを確認します。

方式 復旧時に必要になるもの
外部Secret管理 外部側のバックアップ、認証手段、同期設定
公開鍵で暗号化したSecret 対応する復号鍵と復旧手順
アプリ固有の暗号化 master key、salt、設定値など
内部CA CAまたは中間CAの鍵、証明書チェーン、更新手順
rclone cryptなど 暗号化パスワードと設定

これらの実値を通常の手順書へ書く必要はありません。手順書には、保管責任、取得方法、復元テスト日だけを書き、値はアクセス制御された別の場所で管理します。

鍵のバックアップを、鍵が必要な暗号化ストレージの中だけに置かないことも重要です。

k3sのdatastoreとアプリデータは別に守る

k3sでは、利用するdatastoreによってbackupとrestoreの方法が変わります。SQLite、外部DB、embedded etcdで手順が異なり、datastoreにある機密データを復号するためのserver tokenも復旧に必要です。詳細はk3sのBackup and Restore公式ドキュメントを確認してください。

クラスタのdatastoreを戻せることと、アプリのPVや外部オブジェクトストレージを戻せることは別です。次の2系統として管理すると混同しにくくなります。

  • クラスタ復旧: Kubernetes object、クラスタ設定、datastore、必要なtoken
  • アプリ復旧: DB、実ファイル、Secret、アプリ固有設定

クラスタだけ戻ってPodが作成されても、永続データがなければサービスは復旧しません。反対にデータがあっても、StorageClassやSecretを再現できなければマウントや起動に失敗します。

復旧順序をアプリごとに書く

手順書は、バックアップコマンドの一覧ではなく、依存関係の順番として書きます。

一般的な例は次の通りです。

1. 土台を戻す

  • サーバーまたはクラスタを用意する
  • 必要なCSIドライバーとStorageClassを戻す
  • Secret管理や証明書発行など、先に必要な基盤を戻す

2. アプリの入れ物を作る

  • namespace、CRD、Operatorを適用する
  • PVCを作成する
  • ConfigMapとSecret参照を作成する
  • アプリは必要に応じて停止状態またはreplica 0で準備する

3. データを戻す

  • DBを空の環境へrestoreする
  • 実ファイルをPVまたはオブジェクトストレージへ戻す
  • 所有者とパーミッションを確認する

4. アプリを起動する

  • 復元元と互換性のあるバージョンで起動する
  • 必要なmigrationを実施する
  • readinessだけでなく、ログインや検索などを確認する

5. 外部公開を戻す

  • 内部で動作確認してから公開経路を戻す
  • DNS、TLS、通知、監視を確認する
  • 古い環境と新しい環境の二重書き込みを避ける

アプリによっては、実ファイルより先にDBを戻す、またはその逆が指定されています。公式のbackup・restore手順がある場合は、必ずそちらを優先します。

RPOとRTOを個人環境向けに決める

RPOとRTOは難しく見えますが、個人環境では次の2つの質問に置き換えられます。

  • RPO: 最大で何時間・何日分の更新を失っても許容できるか
  • RTO: 故障してから何時間・何日で使える状態へ戻したいか

例えば、毎日更新するノートと、月に数回しか使わないツールでは、必要なbackup頻度が違います。すべてを同じ頻度と保持期間にすると、容量と保守時間が増えます。

重要度 RPOの考え方 RTOの考え方 対応例
失えない原本 更新間隔より短くする 復旧手順を事前検証する 複数コピー、オフサイト、定期restore
再作成が難しいデータ 1日程度など用途から決める 数時間〜数日 日次dump、世代管理
再生成できるデータ 長くても許容しやすい 必要になってから再生成 cacheや検索indexをbackup対象外にする
一時的な検証環境 backupしない判断も可能 再構築する manifestと手順だけ残す

表の時間は例です。実際の更新頻度、データ量、回線、復旧に使える時間から決めます。

バックアップ棚卸し表を作る

最初から自動化するより、まず1枚の表にすると抜けが見えます。

対象 データ種別 backup方法 保存先の種類 頻度 保持期間 RPO RTO 最終restore確認日
アプリA PostgreSQL custom format dump オフサイト 未記入 未記入 未記入 未記入 未確認
アプリA 添付ファイル snapshot+ファイルコピー 別障害領域 未記入 未記入 未記入 未記入 未確認
クラスタ datastore datastoreに合った公式手順 クラスタ外 未記入 未記入 未記入 未記入 未確認
共通 復旧用の鍵 暗号化して別管理 独立した保管先 変更時 必要期間 対象外 未記入 未確認

「未確認」と書くことに意味があります。空欄を隠さず、失ったときの影響が大きいものから復元テストを進めます。

この表を公開する場合は、実際のサービス名、保存先、頻度、最終実行時刻をそのまま載せず、一般化した例に置き換えます。

復元テストは4段階で小さく始める

レベル1: 1ファイルを戻す

オフサイトコピーから別ディレクトリへ戻し、実際に開きます。暗号化している場合は復号まで確認します。

レベル2: DB dumpを戻す

使い捨てDBへrestoreし、schema、代表的なレコード、文字コードを確認します。稼働中DBには戻しません。

レベル3: アプリ単位で戻す

別namespaceや隔離した検証環境を使い、DBと実ファイルを戻します。ログイン、一覧表示、検索、アップロードなど、日常の操作を確認します。

レベル4: クラスタを失った前提で確認する

bootstrap手順だけでクラスタと共通基盤を作り、アプリを1つ戻します。すべてを毎回復元しなくても、依存関係の多い代表アプリを選ぶと問題を見つけやすくなります。

復元テストでは、次を記録します。

  • 実施日
  • 使ったbackupの作成日
  • 復旧にかかった時間
  • 手順から外れた操作
  • 足りなかった権限、設定、鍵
  • 次回までに直すこと

失敗しやすい点

backupジョブの成功だけを見ている

終了コード0でも、対象ディレクトリを間違えていたり、必要なDBが含まれていなかったりします。件数、サイズ、ハッシュ、restoreを別に確認します。

snapshotをオフサイトbackupだと思っている

同じストレージ障害でsnapshotも失う構成があります。snapshotが物理的にどこへ保存されるかを確認します。

DBと実ファイルの時点がずれている

書き込みを止める、アプリ公式のbackup modeを使う、取得時刻を記録するなど、整合性を取る方法を決めます。

鍵をbackupデータと同時に失う

暗号化鍵や復号鍵を同じクラスタ内だけに置くと、クラスタ全損時に取り出せません。一方、平文で複製しすぎると漏洩リスクが増えます。アクセスできる人と保管場所を絞ります。

新しすぎるバージョンへ直接戻す

DBやアプリのmigrationにより、古いbackupを最新バージョンへ直接戻せない場合があります。まずbackup取得時と互換性のあるバージョンで復旧し、動作確認後に段階的に更新します。

Git、registry、Secret管理まで同時に失う

復旧に必要な道具がすべて同じクラスタに依存すると、最初の一歩が進みません。bootstrapに必要な最小セットだけは、障害対象から独立させます。

セルフホストのバックアップ確認リスト

  • [ ] DB、実ファイル、設定、Secretを分けて把握した
  • [ ] cacheや検索indexなど、再生成できるものを区別した
  • [ ] snapshotとremote backupの違いを確認した
  • [ ] local PVがある場合、ノード消失時の移動方法を決めた
  • [ ] DB dumpを使い捨て環境へrestoreした
  • [ ] DBと実ファイルを近い時点へ戻せる
  • [ ] アプリとDBのバージョンを記録した
  • [ ] Secret管理方式ごとの復旧鍵を確認した
  • [ ] クラスタ外からbootstrapできる
  • [ ] RPOとRTOを用途ごとに決めた
  • [ ] backup失敗を通知できる
  • [ ] 最終restore確認日を記録した
  • [ ] 次の復元テスト日を決めた

まとめ

セルフホストのバックアップは、PVをコピーする作業ではなく、サービスを戻すための設計です。

DB、実ファイル、設定、Secret、クラスタdatastoreは、それぞれ別の方法で守る必要があります。snapshotは短期的な切り戻しに便利ですが、同じ障害で失われるならオフサイトbackupにはなりません。Gitにmanifestがあっても、データと鍵がなければアプリは戻りません。

最初からクラスタ全体の復元を目指す必要はありません。1ファイル、1つのDB、1つのアプリの順で小さく戻し、手順と所要時間を記録します。

バックアップがあるかではなく、最後にいつ、どこまで戻せたかを確認できる状態が、セルフホストを続けるための安心につながります。

次に読む記事

更新履歴

  • 2026-07-12: 新規ドラフト作成
バックアップして終わりにしない――セルフホスト環境の復元テスト入門
http://notes.midnightstops.com/posts/33/
作者
Author
公開日
2026-07-12