第16回で決めたのは、鳴った後に人がどう動くかです。指揮・実作業・連絡の3役を分け、Sev1の一次応答を5分と置き、1シフトあたり2件という負荷の上限から体制を逆算しました。
ただしあの体制は、リージョンが生きていることを前提にしています。リージョンごと失われたとき、必要になるのは新しい体制ではなく、新しい数値です。何分止まってよいのか。何分ぶんのデータを失ってよいのか。その2つが決まらないと、復旧手順は書き始められません。
目次
指揮の体制は変わらない。変わるのは判断に使う数値
本記事は、次の3つの立場を採ります。
- RPOとRTOは目標ではなく制約。数値を書いた時点で、選べる構成が1つに絞り込まれます。願望を書く作業ではありません
- バックアップは「取れているか」ではなく「その日のクラスタに戻せるか」で設計する。保持期間を延ばしても、復元できる期間は延びません
- 復旧は順序の設計。手順の一覧ではなく、なぜその順番なのかを書きます。順番を間違えると、復元そのものが失敗します
先に範囲を切っておきます。本記事が扱うのは、事業継続計画のうちITシステムの復旧部分だけです。要員の安否確認、代替拠点、法務対応は扱いません。総務部から回ってくる雛形と本記事は、埋める欄が違います。
第16回から引き継ぐもの、引き継がないもの
引き継ぐのは、指揮の体制です。指揮担当・実作業担当・連絡担当の3役、システムに変更を加えてよいのは実作業担当だけという原則、引き継ぎは承諾を得るまで回線を切らないという作法。ランブックに入れる5項目も、そのまま使います。
引き継がないものが3つあります。
- Severityの段。リージョン障害はSev1に該当しますが、DRの発動はSevの段では決まりません。判断者も条件も別です(最後の章で確定させます)
- 一次応答の時計。第16回の5分は担当者が反応するまでの時間でした。本記事の時計はRTOで、測る対象が違います
- 1シフト2件という負荷の上限。DRは計画外の1件が数時間続く事象です。件数で測る前提が成り立ちません
検知の経路も第15回から引き継ぎます。リージョン全体の停止を検知できるのは外形監視だけで、クラスタ内から自分自身を叩く構成では、クラスタと同時に止まります。加えて第16回で確認したとおり、クラウドのステータス通知は裏付けであって一次検知ではありません。大規模障害では認証基盤に依存するダッシュボードにログインできない可能性があるため、ランブックには公開ステータスページのURLを書いておきます。
この記事で決める4つの数値と3つの成果物
決める数値は4つです。RPO、RTO、バックアップの保持期間、訓練の頻度。成果物は3つ、RPO/RTO定義表、復旧ランブック、DR訓練の記録様式です。
この4つは独立ではありません。RPOと保持期間は計算式で結ばれ、保持期間と訓練の頻度も結ばれます。1つ動かすと他が動きます。たとえばバックアップの取得間隔を短くすると、ツールによっては保持できる日数が減ります。この関係を知らずに表を埋めると、設定できない組み合わせが設計書に残ります。
本記事は、バックアップの主軸にVeleroを置きます。Google Cloud のマネージドサービスである Backup for GKE は、各節の末尾で対比として扱い、最後に「マネージドに寄せる条件」としてまとめます。
RPOとRTOは目標ではなく制約
Google Cloud の定義はこうです。RTOは「アプリケーションがオフラインでいられる最大許容時間」、RPOは「重大な事象によってデータが失われうる最大許容時間」。そして公式は費用との関係も明記しています。RTOとRPOの値が小さいほど、つまり復旧が速いほど、そのアプリケーションの運用コストは高くなる。
ここから本章の主張が出ます。数値を書くことは、使える構成を絞り込むことです。「RPO 5分」と書いた瞬間に、選べる手段は数個に減ります。
RPOの下限は、選んだ方式が構造的に持つ遅延で決まる
方式ごとに到達できるRPOは、おおよそ決まっています。
| 到達できるRPO | 方式 | 制約 |
|---|---|---|
| 0 | 同期レプリケーション | リージョン障害に対しては実質的に選べない。公式は「RPOゼロの達成とは、主にリージョナルな製品を使うことを意味し、それらは既定でゾーン規模の障害には耐えるがリージョン規模の障害には耐えない」と明記 |
| 約1分 | Compute Engine の非同期レプリケーション | 目標RPOは1分。毎分12.5 GBの圧縮変更ブロックまで、4 KB粒度。RPOは設定できません。VMから切り離されている間は最大5分に延びることがあります |
| 数分(非ゼロ) | Cloud SQL のクロスリージョン・リードレプリカ | 非同期のため「RPOは非ゼロである可能性が高い」と公式が明記 |
| 15分 | Cloud Storage デュアルリージョン+turbo replication | 新規オブジェクトの100%を15分以内に複製する設計。デュアルリージョンのバケットのみ |
| 60分 | Backup for GKE のRPOスケジュール | 指定できる最小値が60分(最大60日)。cronスケジュールなら最小10分間隔 |
| 12時間 | Cloud Storage の既定のレプリケーション | 新規オブジェクトの99.9%を1時間以内、100%を12時間以内。turboを付けなければこれ |
この表の使い方は単純です。設計書に書いたRPOの値を表に当て、その値を実現する方式が残っているかを見ます。「RPO 5分」と書いたなら、候補は同期レプリケーションかディスクの非同期レプリケーションで、バックアップの取得間隔をどう詰めても届きません。
なお Compute Engine の非同期レプリケーションについて、Kubernetes の PersistentVolume で利用できるという記述は公式ドキュメントに見当たりません。本記事では、到達可能なRPOの下限を示す参照値としてのみ扱います。
設計書に書く1行はこうなります。「RPO ◯分」の下に、その値を実現する方式名を必ず併記する。方式のない数値は、検証のしようがありません。

RTOは7工程の直列の和として計算する
「RTO 4時間」と書くとき、その4時間の内訳を分解します。
| 工程 | 値の出どころ |
|---|---|
| ①検知 | 第15回で確認したとおり最短でも約6分30秒(メトリクスの可視化に60秒、アラート評価の遅延に最大5分30秒) |
| ②発動の判断 | 判断者が集まるまでの時間+判断そのものに使う時間(後述の計算式で上限が出ます) |
| ③クラスタの用意 | 常設なら0、再建なら実測値。第8回のTerraformで空のプロジェクトから再現できることが前提 |
| ④バックアップ基盤とGitOpsの起動確認 | 実測値。Velero自体が復旧先クラスタに入っている必要があります |
| ⑤ステートレスの同期 | Argo CDの照合間隔は既定120秒、最大60秒のジッター(手動同期なら即時) |
| ⑥ボリュームとデータの復元 | 容量とボリューム数に比例。マネージドを使う場合、1操作あたりPVC 1,000件が上限 |
| ⑦トラフィックの切り替え | 第13回のDNSキャッシュとコネクションドレイン(ドレインは最大3,600秒、その後の終了まで最大60秒) |
並列にできるのは④⑤と⑥の一部だけで、③は必ず先行します。ボリュームの復元先はクラスタ内のPVCなので、クラスタがなければ始まりません。
ここで時計の起点を決めておきます。混乱の元になる箇所です。
- RTOの起点は障害の発生時刻。検知にかかる6分30秒はRTOの内側に入ります
- RPOの起点は、最後に成功したバックアップの完了時刻。したがってRPOの最悪値は「取得間隔」ではなく「取得間隔+1世代分」です。障害が取得の直前に起きれば、その世代は存在しません
第16回では、一次応答の時計の起点を「通知を受け取った時刻」に置きました。本記事とは逆です。理由が違うためです。一次応答は担当者との約束ですが、RTOは事業側との約束で、事業側から見れば検知の遅れも停止時間の一部です。
②に使ってよい時間も、計算で出せます。RTOから③〜⑦の実測合計と検知の6分30秒を引いた残りが、判断に使える上限です。「発動判断は30分以内に」と根拠なく書くより、この式を設計書に置くほうが実務で使えます。そして③〜⑦の値は、訓練でしか埋まりません。初回は「未計測」と書いて提出してください。空欄のまま数値だけ書くよりはるかに良い状態です。

RPOとRTOの決め方(事業側と技術側の往復)
手順は3ステップです。
- 事業側から降ろす。「何時間止まると、どの契約やどの締め切りに影響するか」「何件の取引を失うと、再入力では復旧できなくなるか」。件数で答えが返ってきたら、ピーク時の毎分件数で割って時間に変換します
- 技術側で検算する。前述のRPOの表と7工程の表に当てます
- 合わなければ、構成を変えるか数値を緩める。この往復を1回で終わらせないでください
設計書に「協議の結果、RTOを◯時間に緩めた」と書ける状態が正しい姿です。
一般的な値は書きません。「RTOは4時間が相場です」と書いた瞬間に、その設計書は自組織の事情を反映しない文書になります。渡すのは決め方だけです。そして第2回のRACIに1行足してください。RPOとRTOの承認者は誰か。これは技術側だけで決められる範囲を超えています。RPO分のデータ損失を受け入れる判断だからです。
Tier分けは、アプリケーションではなく復旧単位に対して行う
Google Cloud は復旧目標の例をティアの形で示しています。ただし公式自身が「仮想のティアに基づく例に過ぎない」と断っています。標準ではありません。議論の出発点として使います。
| ティア | 全体に占める割合 | 例 | ゾーン障害 | リージョン障害 |
|---|---|---|---|---|
| Tier 1 | 5% | グローバルまたは外部顧客向け(リアルタイム決済、ECのストアフロント) | RTO 0 / RPO 0 | RTO 0 / RPO 0 |
| Tier 2 | 35% | リージョナルなアプリ、重要な社内システム(CRM、ERP) | RTO 15分 / RPO 15分 | RTO 1時間 / RPO 1時間 |
| Tier 3 | 60% | 部門内のアプリ(バックオフィス、休暇申請、経費、人事) | RTO 1時間 / RPO 1時間 | RTO 12時間 / RPO 12時間 |
この表で見るべき点は2つあります。
1つ目は、列が2つあることです。ゾーン障害とリージョン障害で別の数値を持っています。RPO/RTOを1組しか書かない設計書は、ゾーン障害に過剰な要求を、リージョン障害に実現不能な要求を、同時に課すことになります。
2つ目は、割合の列です。Tier 1は全体の5%という例が示されています。すべての復旧単位をTier 1に置いた定義表は、定義として機能しません。この列があると、会議で「全部最優先」という結論を避けられます。
ティアを付ける単位は、アプリケーションではなく復旧単位です。判定条件は3つ。①データを共有しているか ②片方だけ戻すと業務データの不整合が起きるか ③同じRPO/RTOを要求されるか。①か②に該当するなら同じ復旧単位にまとめます。③だけが一致していても、まとめる理由にはなりません。単位は第2回の所有権と第4回のラベリングに揃えてください。ずれると、復旧の途中で誰に確認すればよいのかが分からなくなります。
そしてTier 1(リージョン障害に対してRPO 0)を選んだ単位があるなら、その時点でKubernetesのバックアップの話ではなくなります。同期レプリケーションを持つデータストアの選定に戻ります。第6回と第7回の管轄です。
DRを発動した月、SLOは達成できない
第3回で選んだリージョンクラスタのSLAは99.95%、許容ダウンタイムは月21.6分です(99.9%なら43.2分、99.99%なら4.32分)。
ここにRTOを重ねます。RTOをTier 2相当の1時間と置いた場合、1回の発動で月間バジェット21.6分の約3倍を消費します。桁の問題ではなく、定義上そうなります。
したがって決めるべきことは1つです。リージョン障害をSLOの対象に含めるかどうか。
- 含めるなら、99.95%は宣言できません。宣言するなら、リージョン障害でも1時間以内に復旧できる構成(常設のDRクラスタと容量の予約)が要ります
- 含めないなら、「災害は別枠」という合意を第3回のSLO定義に遡って書き足します
本記事は、対象から外して別枠のDR目標で管理する立場を既定とします。多くの組織がそうしていますが、書いていないことがほとんどです。書いていないと、発動した翌月にSLOの未達が報告され、原因の欄に「災害」と書かれ、そこで議論が止まります。
第16回では、同じ「放置時間とエラーバジェットの比較」から逆の結論を出しました。夜間のSev2を翌営業日まで持ち越してよいかを判断したとき、バジェットを消費し続ける事象は縮退の対象にできないと結論づけています。DRでは逆に、バジェットの枠外に置く合意を取ります。違いは頻度です。日常のインシデントは月に何度も起きますが、リージョン障害は年に何度も起きません。年に1回の事象を月間バジェットに含めると、その月だけが常に未達になり、指標として機能しなくなります。
RTOはSLOから導けません。SLOから導けるのは、DRを発動しない範囲までです。
何を、どこから戻すのか
復旧計画の1行目は、手順ではなく対象の仕分けです。戻し先が4種類あり、それぞれ道具も所有者も所要時間も違います。
復旧対象は4種類に分かれる
| 対象 | どこから戻すか | 根拠 |
|---|---|---|
| クラスタそのもの(ノードプール、初期サイズ、有効な機能、VPC、IP範囲) | Terraform(第8回) | Backup for GKE の対象外4項目の1つ。Veleroも同様にクラスタ自体は作れません |
| ステートレスなワークロード | Git(第9回・第10回) | GitOpsで同期されます。ただしイメージが引ける前提 |
| ステートフルなデータ(PV) | Velero(マネージドの対案は Backup for GKE) | 本記事の主対象 |
| クラスタ外のサービス(Cloud SQL、Secret Manager、Artifact Registry、ロードバランサ) | 各サービスのDR機能 | クラスタのバックアップには含まれません |
第7回では、Backup for GKE の対象外を4項目挙げました。対象外の列挙で終わらせず、行き先まで書くのがこの表です。行き先の書いていない対象外リストは、読んだ人に「気をつけよう」しか残しません。
クラスタそのものはバックアップされない
Veleroは復旧先のクラスタにインストールされている必要があります。つまりクラスタが先に存在します。Backup for GKE の復元計画も、既存のターゲットクラスタを指定する形式です。どちらのツールも、クラスタを作る機能を持っていません。
したがってRTOの③(クラスタの用意)を担当するのは、バックアップツールではなく第8回のIaCです。ここで第8回の完了条件が効いてきます。「applyが通ること」ではなく「空のプロジェクトから再現できること」。DRの作業内容は、空のプロジェクトからの再現そのものです。第8回で再現テストをしていないなら、その時点でRTOは未知数です。
第3回のIPアドレス計画も、DRリージョンぶんが必要です。ノードあたりの最大Pod数は作成後に変更できず、Podのセカンダリ範囲から最大ノード数が決まります(/21かつ110 Pods/nodeで最大8ノード)。本番と同じ規模を立てられる範囲を、DRリージョンにも確保しておいてください。復旧の当日に9台目が立たないという形で表面化します。
ステートレスはGitにある。ただしイメージが引ければ
マニフェストがGitに揃っていても、復旧先で同じダイジェストのイメージが引けなければPodは起動しません。第9回で「デプロイの参照方式、昇格の単位、署名の対象はすべてダイジェスト」と決めているため、タグの付け替えでは救済できません。
Artifact Registry のリポジトリはリージョンまたはマルチリージョンに置かれます。公式は「マルチリージョンのリポジトリは、片方のリージョンが停止していても動作を続ける可能性がある。ただしそのリポジトリに運用上の障害が起きた場合は、リージョンに関係なくすべての利用者が影響を受ける」と書いています。
設計書に書く1行は、復旧先から参照するレジストリのロケーションと、そこにイメージが存在することを確認する手順です。第9回のクリーンアップポリシーには「削除条件と保持条件の両方に合致する場合は保持が優先される」という性質があるので、DRで必要な世代を保持条件で守ります。スキャン結果が30日で古くなり90日でアーカイブされることも第9回で確認済みですが、古くなることと消えることは別です。消える設定になっていないかを見てください。
クラスタ外のサービスは、それぞれのDR機能で戻す
Secret Managerのレプリケーションポリシーには、Googleが複数リージョンへ複製する automatic と、指定したロケーションにのみ複製する user-managed があります。ここに落とし穴があります。公式は「レプリケーションポリシーのロケーションは更新できません」と明記しています。作成時にしか決められません。user-managed を選んでDRリージョンを含めていなければ、そのシークレットはDR先で読めません。
これは単独の落とし穴ではなく、類型です。DRに効く設定の多くは作成時にしか選べません。第3回のノードあたり最大Pod数、Cloud Storage のバケットのロケーション(移設は可能になりましたが Storage Intelligence の構成が前提です)、Artifact Registry のリポジトリのロケーション、そして暗号鍵のリージョン。DR設計を後回しにすると、直すために作り直しが必要な項目が積み上がります。
Cloud SQLはクロスリージョン・リードレプリカで戻します(後の章で詳述します)。ロードバランサとDNSは第13回で確定した数値をそのまま使います。ヘルスチェックの間隔は30秒から300秒、コネクションドレインは最大3,600秒、重み0のターゲットは常に健全とみなされる、といった性質です。
バックアップは「取れているか」ではなく「戻せるか」で設計する
第7回で決めたバックアップの完了条件は「復元テストに成功したこと」でした。取得できたことではありません。本章では、その完了条件を満たすための設定値を決めます。
保持と取得間隔は、自分で決めて自分で守る
第7回で決めた記入項目は、対象・頻度・保持世代・保存先リージョン・暗号化の要否の5つでした。頻度と保持世代は「データを壊したことに気づくまでの時間」から決めるという基準まで確立しています。本記事はその決め方に戻りません。足すのは2つだけです。RPOという第2の入力と、設定が成立するための制約。
ここで衝突が起きます。取得間隔という1つの設定項目を、2つの要求が奪い合います。第7回の「気づくまでの時間」と、本記事の「RPO」です。決まるのは厳しいほうです。設計書には両方の根拠を並べて書いてください。後から緩めるときに、どちらの要求が緩んだのかが分かります。
Veleroで決める設定は2つだけです。スケジュール(cron形式)と、各バックアップのTTL(既定30日)。バックアップの名前は「スケジュール名とタイムスタンプ」の組み合わせで自動的に付きます。
そして整合を止める仕組みがありません。「1時間ごとに取得してTTL 30日」と書けば、そのまま720世代が積み上がります。保管費用はオブジェクトストレージの請求として、翌月に現れます。削除も即座には効きません。不要になったバックアップの回収は既定で1時間ごとなので、消したはずのものがしばらく残って見えるのは正常な挙動です。
したがって設計書には、取得間隔・TTL・想定世代数・月額の保管費を1つの表として書きます。これがVeleroを選んだ場合の最初の宿題です。マネージドなら設定の段階で弾かれる矛盾を、自分の文書で止めることになります。
対比として、マネージドではどうなるかを見ておきます。Backup for GKE には「保持期間は作成間隔の360倍以下」という制約が設定側にあります。ここから2つの計算が出ます。
- RPOを最小値の60分にすると、保持できるのは360時間、つまり15日が上限になります
- 日次取得の保持上限は360日です。保持日数の最大値は365日ですが、「毎日取って1年保持」は設定できません(365日保持には約24.3時間以上の間隔が要ります)
ほかに、保持日数は削除ロック日数(0から90日)より大きい必要があること、cronの最小間隔が10分であること、そしてcronの時刻がすべて協定世界時として解釈されることが公式に明記されています。日本時間の深夜3時のつもりで指定すると、実際には正午に走ります。この最後の点はVeleroのスケジュールでも同じ検討が要ります。設計書にはタイムゾーンを必ず明記してください。
保持の上限を決めているのは、APIバージョンの窓
ここが本記事で最も重要な導出です。
Veleroが既定でバックアップするのは、取得時点のクラスタにおける優先APIグループバージョンだけです。複数のバージョンを保存する機能はありますが、フィーチャーフラグでの有効化が必要で、しかも取得側と復元側の両方で有効にする必要があります。復元先については、公式が「バックアップ元より低いKubernetesバージョンのクラスタへは復元できない」と明記しています。
ここに第14回で確定した2つの数値を重ねます。ベータAPIは非推奨化から9ヶ月または3マイナーリリースの長いほうで提供停止、GKEのマイナーリリースは年3回。
突き合わせると、こうなります。1年前に取得したバックアップに入っているマニフェストのAPIバージョンが、復元先のクラスタでは既に提供されていない状態が起こりえます。
保持期間を延ばしても、復元できる期間は延びません。これは公式に書かれた結論ではなく、複数の一次情報からの導出です。材料はすべて公式に明記されています。
設計上の帰結は2つです。
- バックアップに含まれるAPIバージョンを棚卸しの対象に加える。第14回でベータAPIの棚卸し台帳を作りました。四半期に一度見る対象に、バックアップも入れます
- 古い世代は「そのまま復元する」のではなく、マニフェストはGitの現行版から作り直し、データだけを戻す経路を用意する。本記事の「ステートレスはGit、ステートフルはバックアップ」という分担は、古い世代ほど強く効いてきます
マネージドを選ぶと、制約の形が変わります。Backup for GKE の復元先クラスタのバージョンは「バックアップ元のバージョンから3マイナーまで」に制限されます(公式の例では、1.28で取得したバックアップは1.28から1.31にのみ復元できます)。年3回のリリースと重ねると、約1年で窓の外に出ます。結論は同じですが、上限が数値で明示されている点はマネージドの利点です。Veleroでは、同じ上限が見えない形で存在します。
「1年分残してあります」は、復元できる保証にはなりません。
ボリュームの取り方は2通りで、整合性のレベルが違う
Veleroがボリュームを取る方法は2通りあります。CSIスナップショット方式と、ファイルシステムバックアップです。後者の内蔵アップローダはKopiaで、node-agentという名前のDaemonSetが必要になります。
公式はファイルシステムバックアップについて、「稼働中のファイルシステムからデータをバックアップするため、同一時点で取得されず、スナップショット方式より整合性が低い」と明記しています。加えて、重複排除のために差分を探す都合上、データベースを格納するような大きなファイルはスキャンに長い時間がかかるとも書かれています。
選択方式も設計項目です。既定はオプトインで、Podのアノテーションに対象ボリューム名を書いたものだけが取得されます。フラグを付ければオプトアウト(既定で全部取得し、除外だけ書く)に変えられます。オプトインの既定は「書き忘れたボリュームは取られない」という意味です。第10回の共通Chartにアノテーションの既定値を持たせるか、第5回のポリシーで必須化するかを決めてください。なおhostPathボリュームは非対応です(ローカル永続ボリュームは対応します)。
どちらの方式でも、メモリ上のデータは取れません。アプリケーション整合が要るならフックを書きます。Veleroのフックはアノテーションで指定し、タイムアウトの既定は30秒、失敗時の挙動の既定は失敗扱いです。実行順序は、対象のPodすべてに事前フックを流し、バックアップを取り、事後フックを流す、という順です。
ここに判断が要ります。フックを書くと、バックアップが失敗しうる経路を自分で作ることになります。30秒でフラッシュが終わらないデータベースでは、タイムアウトを延ばすか、失敗を無視する設定にして整合性を諦めるかを、明示的に選びます。そしてバックアップの失敗を検知するアラートが必須になります。第15回のアラート設計に1行追加してください。失敗に気づかなければ、その世代は存在しないのと同じです。
マネージドでも同じ判断からは逃げられません。Backup for GKE も、専用のカスタムリソースを使わなければクラッシュ整合(ある時点でディスクに書き終わった内容は取得されるが、メモリ上のデータは含まれない)で、フックの既定値も30秒と失敗扱いで同じです。
保存先は2つ決める。ここがDR設計の要
Veleroの保存先は2つあります。構成のバックアップを置くオブジェクトストレージと、ボリュームスナップショットの保存先です。両方をDR前提で決めます。
前者では、Cloud Storage のロケーション設計がそのまま効きます。
| バケットの構成 | 別リージョンへ複製されるまでの目標 | リージョン障害時 |
|---|---|---|
| リージョン | 複製されません | 読めません。DR計画として成立しません |
| デュアルリージョン(既定のレプリケーション) | 新規オブジェクトの99.9%を1時間以内、100%を12時間以内 | 利用でき、パスの変更も要りません |
| デュアルリージョン+turbo replication | 100%を15分以内 | 同上 |
「バックアップの保存先が落ちていて復旧を始められない」という事態は、バケットのロケーション選択で回避できます。本番と同じ単一リージョンにだけバックアップを置く構成は、復旧の入力が失われた対象と同じ事象に依存するため、DR計画として成立しません。
ここで1つ、混同しやすい点を書いておきます。この表の15分や12時間は「バックアップの複製が別リージョンに届くまでの時間」であって、業務データのRPOではありません。バックアップが取れてから複製されるまでの時間です。RPOの計算には、取得間隔のほうが効きます。
もう1つ、バックアップの置き場所をクラスタのプロジェクトから切り離すという選択があります。別のプロジェクトに置けば、クラスタのプロジェクトを操作できる権限だけではバックアップを消せません。第5回のRBACと第8回のIAMの延長にある設計です。ただしマネージドのクロスプロジェクト復元はプレビュー段階なので、復旧の主経路には置かないでください。隔離の手段として使い、戻す経路は同一プロジェクト側に残します。
災害時の操作も1つ決めておきます。保存先を読み取り専用に切り替えます。Veleroの公式手順にも、災害時にバックアップの保存先を読み取り専用へ変更し、復旧後に書き込み可へ戻す流れが明記されています。復旧作業中にバックアップが削除されることを防ぐためです。手順の最初と最後に1行ずつ置く形は、次章のGitOpsの停止と再開とまったく同じ構造です。
もう一方の保存先、ボリュームスナップショットの置き場所は、GCPのプラグイン設定で指定します。指定しなければプラグインの既定のロケーションです。リージョンをまたぐ復元に対応すると明記した公式の記述は見当たらないため、本記事では「訓練で確認する項目」として扱います。公式が「対応していない」と名指ししているのはAWSとAzureのプラグインで、その場合はファイルシステムバックアップを使えとされています。逃げ道はそこにあります。ファイルシステムバックアップならデータはオブジェクトストレージに入るため、前掲の表のロケーション設計だけで解決できます。
マネージドの場合はどうか。Backup for GKE のアーティファクトの保存先は、バックアップ計画に指定した1リージョンです。クラスタと別リージョンには置けますが、保存先そのものを冗長化したければ計画を2本持つことになり、費用はおおよそ2倍になります。復元計画のターゲットクラスタは復元計画と同じリージョン内である必要があり、顧客管理の暗号鍵を使う場合、鍵はバックアップ計画と同じリージョンに置く必要があります。保存先をDRリージョンに置けば鍵もそちらに置かれるので、本番リージョンの障害で鍵が読めなくなる経路は生まれません。
マネージドに寄せる条件
否定ではなく条件で書きます。次の3つがすべて当てはまるなら、マネージドが妥当です。
- GKEのみで完結する(別のクラウドや別のディストリビューションへ復元する要件がない)
- 保持と取得間隔の整合を、設定側に持ってほしい(前述の360倍のような制約に守られたい)
- 運用工数を増やせない(第6回で数えた3費目のうち、運用工数の枠が空いていない)
逆に、Veleroを選ぶと引き受けるものを一覧にします(第6回で決めた「マネージドを却下した場合に引き受ける作業の一覧」です)。
| 項目 | 引き受ける内容 |
|---|---|
| 配置 | node-agent(DaemonSet)の配置。ファイルシステムバックアップを使うなら必須 |
| 認証 | Workload Identity とサービスアカウントのアノテーション。ディスクのスナップショット作成、スナップショットの読み取り、オブジェクトの書き込みといった権限を自分で設計します |
| 保管の設計 | TTL(既定30日)と取得間隔の整合を自分で保つ。世代数と保管費の計算 |
| 鍵の扱い | リポジトリの暗号化は静的な共通鍵です。公式が「バックアップストレージにアクセスできる者は誰でもバックアップデータを復号できる」と明記しています |
| バージョン | 本体とプラグインの更新計画。下位バージョンのクラスタへは復元できません |
| 待ち時間 | 別クラスタからバックアップが見えるまで既定1分、削除の反映は既定1時間ごと。復旧手順の待機時間として書きます |
| 失敗の検知 | バックアップ失敗のアラート(第15回) |
4行目が最も重い項目です。バケットのアクセス制御が、事実上のデータ保護の境界になります。第8回のtfstateと同じ構造です。見返りは3つ、保存先を自分で選べること、別のクラスタや別のディストリビューションへ復元できること、復元の粒度と順序を細かく制御できること。選定の記録は第6回の形式でADRとして残してください。本記事が渡すのは選定の入力までです。
クロスリージョン復旧は、順序の設計
本章は手順書そのものではなく、手順の順番がなぜその順番なのかを扱います。順番の根拠が書かれていない手順書は、想定外の状況で並べ替えられ、そこで失敗します。
復旧の順序(この順にしか進めない)
先ほどRTOを7工程に分解しました。それを実務の粒度に開くと、次の10段になります。
- 発動を判断する(最後の章で条件を決めます)
- DRリージョンのクラスタを用意する。常設なら起動確認、再建ならTerraform。Velero自体がそのクラスタに入っている必要があります
- バックアップの保存先を読み取り専用にし、バックアップが見えることを確認する。別クラスタからの同期は既定1分間隔なので、見えるまでの待ち時間が手順に入ります
- GitOpsの自動同期を止める(次の節)
- カスタムリソース定義とクラスタスコープのリソースを先に戻す(その次の節)
- ステートレスをGitから同期する
- ボリュームとデータを復元する
- アプリケーションの整合を確認する。起動しただけでは終わりません
- トラフィックを切り替える(第13回)
- GitOpsの自動同期を戻し、保存先を書き込み可へ戻す。最後の作業は後片付けです
2と7を並列にできない理由は単純です。ボリュームの復元先はクラスタ内のPVCなので、クラスタがなければ始まりません。
第2回のRACIには1行足してください。この手順の各段を、誰が実行してよいのか。運開分離をしている環境では、本番に書き込める人が限られます。第5回で設計した緊急時の権限昇格と、第16回で決めたその有効期限(1件あたり平均6時間を既定とし、超えるなら延長ではなく再申請)が、ここで実際に使われます。
GitOpsの自動同期を止めてから復元する
Google Cloud の公式トラブルシューティングに、こういう事象が載っています。復元したリソースが、GitOpsコントローラ(Config Sync、Argo CD、Flux)によって削除され、復元操作が「リソースが見つからない」で失敗する。対処として、監査ログで削除元を特定し、自動化を一時停止せよと書かれています。
これはマネージドの資料に載っている事象ですが、原因はGitOpsコントローラ側にあるため、Veleroで復元しても同じことが起きます。
Argo CDの既定値を確認しておきます。Gitから消えたリソースの自動削除は既定で無効(公式は「安全機構として」と書いています)、クラスタ側の変更を検知して同期し直す動作も既定で無効です。照合の間隔は既定120秒に最大60秒のジッターが加わります。
問題は、第9回で本番を自動同期に倒した構成では、この2つを両方とも有効にしている運用が多いことです。有効なら、復元でクラスタ上に現れたGitにないリソースは削除対象になります。復旧の最中に、3分おきに自分の作業が取り消される状態が生まれます。
したがって復旧ランブックには、「自動同期の停止」と「復旧完了後の再開」を明示的な2行として入れます。止めたまま忘れると、以後の変更が反映されない状態が残ります。第13回で「移行の最後の作業は旧環境に紐づいた設定の削除」と書いたのと同じ構造です。元に戻す作業を、手順の末尾に置いてください。
ここでステートレスとステートフルの境界を引き直します。境界は「Gitに書いてあるか」ではなく「復元で上書きされてよいか」です。Deploymentまでバックアップから戻すと、Gitと二重管理になります。復元スコープは、Gitにない実行時のリソースとボリュームに絞ります。
復元スコープと競合ポリシーの既定値を決める
Veleroで決める項目は4つです。設計書に既定値を書き、例外だけ運用で変えます。
| 項目 | 選択肢 | 既定として推奨するもの |
|---|---|---|
| 既存リソースがある場合 | スキップ(既定)/既存をパッチして更新 | スキップのまま。ただし「復元したのに変わっていない」の原因になるため、この挙動を手順に明記します |
| 復元の順序 | 既定はカスタムリソース定義、Namespace、StorageClassの順から。フラグで変更可 | 既定に自環境の依存を追加(前節) |
| 復元先のNamespace | そのまま/別名に付け替え | DRでは付け替えない。訓練で本番と別のNamespaceに戻す場合にだけ使います |
| 復元対象の範囲 | Namespace単位・ラベル単位のフィルタ | Gitで管理している範囲を除いた選択Namespace |
2行目の順序には、公式のトラブルシューティングに載っている失敗が関係します。検証用または変更用のAdmission Webhookが有効なのに、そのバックエンドのサービスが復元時にまだ起動していないと、復元しようとしたリソースの作成がwebhook呼び出しの失敗で止まります。第5回で導入したポリシーエンジンが、このwebhookにあたります。平常時にルール違反のマニフェストを止めてくれるものが、復旧時には障害物になります。対処は、webhookに依存するコンポーネントを先に復元するよう順序を変えるか、webhookの実体を先に戻してから残りを戻す2段階にするかの2つです。どちらを採るかを設計書に書いてください。復旧の当日に考える種類の判断ではありません。
1行目も補足します。Veleroの復元は既定で非破壊です。ターゲットクラスタに同名のリソースがあれば、そのリソースの復元はスキップされます(ServiceAccountだけはマージが試みられます)。空のクラスタへ戻すDRでは問題になりませんが、部分的な復旧では「戻したつもりで戻っていない」が起きます。
細かいところでは、ターゲットクラスタに同名のPersistentVolumeがあり、かつクレームのNamespaceを付け替えている場合、PVは自動的に別名に改名されます。手順書でPV名を前提にした確認をしていると、ここで詰まります。自動割り当てされたNodePortも既定では削除され、保持するオプションを使うとポートが競合したときにエラーになります。
マネージドの場合、復元計画にはボリュームデータの復元方針、Namespaceスコープの競合時の挙動(5種類)、クラスタスコープの競合時の挙動が設定項目としてあります。既定として推奨するのは競合時はスキップと既存のクラスタリソースを優先です。既存を削除してから復元する設定は空のクラスタ以外では選ばず、バックアップ側のバージョンでクラスタリソースを置き換える設定は、カスタムリソース定義を置き換えたときに紐づくカスタムリソースがすべて削除されるため、既定にしません。
規模の上限も押さえておきます。マネージドではPVCは1操作あたり1,000件、リソースは種類あたり20,000件、フィルタ条件は包含と除外あわせて50件、APIは毎分1,200リクエストという上限があります。大規模なクラスタでは復元を分割する設計が要るという結論は、どちらのツールでも変わりません。分割するなら、分割の単位は復旧単位に合わせます。
切り替え先に容量があるとは限らない
ここは見落とされやすい箇所です。Googleは明言しています。「重要なワークロードの容量を確保するには、DR対象のゾーンに予約を作成すべきである。予約がなければ、RTOを満たすために必要なオンデマンド容量を取得できない可能性がある。」
そして予約は、使っていなくても実行中のVMと同じ料金で課金されます。予約はゾーン単位で、公式が挙げている用途には「成長、移行、災害復旧」が並んでいます。
費用を3段階で並べます。これは体制の話ではなく設備の話なので、金額で比較して構いません。
| 構成 | 平常時の費用 | RTOへの影響 |
|---|---|---|
| ①DRリージョンに何も置かない | バックアップの保管費のみ | クラスタ再建の実測値が丸ごと乗ります。未計測なら宣言できません |
| ②クラスタだけ常設(最小ノード) | クラスタ管理手数料が1時間あたり$0.10、月に約$73+最小ノード分 | 再建の時間が消え、バックアップ基盤とGitOpsの起動も済んでいます |
| ③容量を予約 | ②+予約したノード分の全額 | 容量の不確実性が消えます |
本記事は②を既定として推奨します。①はRTOの内訳のうち2工程が実測不能なまま残り、結果として「RTO 4時間」が検証されない数値になりやすいためです。①を選ぶなら、RTOが前掲のTier 3相当(リージョン障害で12時間)まで緩められることを先に確認してください。
金額の桁を1つ出しておきます。第7回で確認したマネージドの公式計算例は8つのNamespaceと200 GiBで月$81でした。ここに②の常設クラスタの月約$73を足すと、ノード費用を除いて月約$154です。この数字を出す目的は安いと言うためではなく、経営層との会議で「DRの下限費用はこの桁です」と即答できるようにするためです。ノードと予約の費用は構成で桁が変わるので、自組織の値を表に入れてください。
第4回で決めた割引の使い方も、そのまま適用できます。コンピューティング フレキシブル確約利用割引は1年28%、3年46%で、任意のリージョンとプロジェクトに適用されるため、DRリージョンの常設分を押さえるのに使えます。ただしDR用のノードにSpotを使わないでください。第1回の条件2と第4回の判定軸で確認したとおり、中断されうるものを復旧の受け皿にはできません。
ステートフルデータの復旧は、K8sの外側から決まる
第7回の選択が、ここで手順の本数を決める
第7回でマネージドDBを選んだ範囲は、本章のPV復旧手順の対象外です。Cloud SQL のDR機能で戻します。Veleroの手順が必要になるのは、第7回でStatefulSetを選んだ範囲だけです。
そして第1回の条件1(ローカルI/O依存)で残ったワークロードが、ここに集まっています。第1回でクラスタに載せると判定し、第7回でStatefulSetを選び、第17回でその復旧手順を書く。3回にまたがって同じ対象を追いかけています。
設計書に書く1行は、復旧単位ごとの「データの所在」列です。PVなのか、マネージドDBなのか、オブジェクトストレージなのか。この列が空欄の復旧単位は、手順を書けません。
マネージドDBの復旧は、昇格の一択ではない
Cloud SQL のクロスリージョン・リードレプリカは非同期です。公式も「クロスリージョン・リードレプリカのRPOは非ゼロである可能性が高い」と書いています。
切り替え方は2つあり、性質が違います。
- レプリカの昇格。即座に切り替えられますが、レプリケーションの遅延があるとデータ損失を伴いえます。リージョン障害時はこちらです
- 計画された切り替え。プライマリを読み取り専用にして遅延がゼロになるのを待つため、データ損失がありません。訓練やメンテナンスで使います
ここから設計項目が1つ出ます。レプリケーションの遅延を監視項目に入れてください(第15回のダッシュボードに1行)。RPOの実測値は、この遅延そのものです。遅延を見ていない状態で「RPOは数分」と書くことはできません。平常時の遅延の中央値と最大値を持っていれば、発動の判断をする時点で、失われるデータ量をその場で見積もれます。
昇格したら終わりでもありません。公式は「完全なDRプロセスでは、新しいプライマリとなった単一のインスタンスを、あらためて高可用性構成にする」ことを求めています。昇格直後の状態は、冗長性のない単一インスタンスです。そして元のリージョンへ戻すには、逆向きのクロスリージョン・レプリカを作り直す必要があります。
PVの復元で、実際に失敗するのはここ
Google Cloud の公式トラブルシューティングには、復元で実際に起きる失敗が列挙されています。マネージドの資料に載っているものですが、原因はクラスタ側とクラウド側にあるため、Veleroで復元しても同じ失敗が起きます。そのまま事前確認リストとして使えます。
| 失敗 | 原因 | 事前に潰す方法 |
|---|---|---|
| ボリュームの復元が失敗する | 永続ディスクのクォータ不足、ディスク作成権限の不足、暗号鍵の使用権限の不足、StorageClassのバインド設定の不整合 | DRリージョンのクォータを本番と同じ値まで引き上げておきます(クォータはリージョン単位)。権限は訓練で確認します |
| ボリュームの復元がタイムアウトする | 最初に使うPodがスケジュールされるまでバインドを待つ設定になっている | 第7回でこの設定を推奨しているため、復元時はPodが起動できる状態を先に作ります |
| ワークロードが期限内に準備完了にならない | イメージの取得失敗、起動直後の異常終了、リソース不足、初期化コンテナの失敗、ConfigMapやSecretの不足 | イメージの到達性とSecretの存在を先に確認します。第11回のProbe設計がそのまま効きます |
| 復元したリソースが見つからない | GitOpsコントローラによる削除、手動削除、ガベージコレクション | 自動同期の停止(前章) |
この一覧そのものが、第7回で決めた完了条件の根拠です。バックアップの成功は、復元の成功を何も保証しません。ここに並んでいる失敗は、どれも実際に復元して初めて出ます。
1行目のクォータは特に見落とされます。クォータはリージョン単位です。第4回では「先に当たるのはIPアドレスの上限」と書きましたが、DRではそれに加えてディスク容量のクォータが先に当たります。本番リージョンで使っている容量と同じだけ、DRリージョンにも枠が要ります。枠の引き上げは申請してから時間がかかるため、復旧の当日には間に合いません。
発動を決める人と、戻せなくなる時点
発動の条件は「障害の大きさ」ではなく「現地復旧の見込み時間」
第16回では、リージョン全体の障害はSev1に該当するが、DRの発動判断は別のプロセスであると書いて留保しました。ここで確定させます。
判定の入力は第15回の外形監視です。クラウドのステータス通知は裏付けとして使います。第16回で確認したとおり、大規模障害では認証基盤に依存するためダッシュボードにログインできない可能性があり、通知の第一報には影響を受けたプロダクト名しか含まれないことも多いためです。
判定の条件は、現地での復旧見込み時間がRTOを超えることです。障害が大きいから発動するのではありません。発動そのものにコストがあるからです。RPO分のデータ損失、不可逆な昇格、そして後日のフェイルバック作業。待って直るなら、待つほうが安く済みます。
この判断を支える事実が1つあります。Google Cloud の公式ドキュメントは、「一時的な障害の間に、影響を受けたロケーションへ書き込まれ、まだ他のロケーションへ複製されていないデータは、障害の解消後に利用可能になるのが一般的である。つまり恒久的なデータ損失のリスクは、障害中にデータへアクセスできなくなるリスクより低い」と書いています。慌てて発動しないことの根拠になります。
判断者は、第16回の指揮担当だけでは足りません。RPO分のデータ損失を受け入れる判断であるため、事業側の意思決定者を含めます。第2回のRACIに「DR発動」の行を追加してください。技術側だけで決めてよい範囲ではありません。
判断そのものにも制限時間を置きます。「発動しない」という判断を保留し続けると、RTOの残り時間が消えます。第13回のGo-Live判定に「切り戻し可能性の残り時間」を入れたのと同じ形で、判定会議の入力にRTOの残り時間を入れてください。上限は前述の計算式(RTOから復旧工程の実測合計と検知の6分30秒を引く)で出ます。
最後に代理者を先に決めておきます。判断者が連絡不能な場合の順序です。引き継ぎの作法は第16回のものをそのまま使います。役割を明示し、承諾を得るまで回線を切りません。
DRを発動した時点で、戻せなくなるものがある
本連載で4回目の同じ形です。第13回の移行のプロモート、第14回のコントロールプレーンの更新、第16回のシークレットの破棄。いずれも、手順のどこかに「戻せなくなる時点」があります。
DRで戻せなくなるものは3つです。
- マネージドDBのレプリカ昇格。元の構成には戻らず、逆向きのレプリカを作り直すことになります
- 切り替え後に旧環境で受けた書き込み。第13回で作った「同期できないデータの一覧」がそのまま使えます
- 復元時に既存を削除する設定や、バックアップ側のバージョンで置き換える設定を選んだ場合の既存リソース。特にカスタムリソース定義を置き換えると、それに紐づくカスタムリソースがすべて削除されます
設計書には1行、「この手順のどこから戻せなくなるか」を書いてください。第13回と第14回で確立した書き方を、そのままDRにも適用します。
そしてフェイルバックは、もう一度の移行です。元のリージョンへ戻す作業は新規の移行プロジェクトであり、第13回の移行計画をそのまま適用できます(切り戻せなくなる時点から逆算する、完了条件は観測値で書く、同期できないデータの一覧を先に作る)。フェイルバック計画のないDR計画は、DRリージョンを恒久的な本番にします。そしてそのリージョンにはDRがありません。元のリージョンの復旧が確認できてから何日以内に判断するかを、先に書いておいてください。
訓練の頻度は、保持期間と構成変更の頻度から決める
「四半期に1回」と書く前に、3つの条件から決めます。
- 保持期間より短い間隔で実施する。前回検証した世代が期限切れになる前に、新しい世代を検証します
- APIバージョンの窓が閉じる前に実施する。GKEのマイナーは年3回進みます
- 構成を変えたら実施する。StorageClassの変更、暗号鍵の導入、Namespaceの追加、GitOpsの同期設定の変更は、どれも復元の経路を変えます
ゾーン障害の訓練には、GKEの公式手順があります。ノードプールのゾーンを減らす、単一ゾーンのノードプールを作って削除する、ノードをスケジュール不可にして退避させる、の3方式です。ただし公式は「ノードプールの削除中、ワークロードは停止して別のノードプールへ再スケジュールされ、その間ServiceとDeploymentは利用できない」と明記し、ノード上のPodDisruptionBudgetがドレインを妨げることがあるとも書いています。第11回で確認した「PDBに期待してよいのは遅らせることだけ」が、訓練の場面でも同じ形で現れます。そしてこの手順は本番では実施できません。
リージョン障害はさらに再現できません。したがって訓練は「DRリージョンで実際に復元する」という形でしか実施できません。実施体制は第12回のカオステストのものを流用します。承認者、中止条件、復旧手順を先に書いてから実施する形です。
完了条件は第7回を継承します。「復元できたこと」ではなく「復元したデータでアプリケーションが起動し、業務上の整合が確認できたこと」。この「業務上の整合」を抽象語のまま残さないでください。確認項目を3つ指定します。
- 復元時点の直前に登録したはずのデータが存在するか(これがRPOの実測値になります)
- 採番や連番に重複と欠番がないか
- 外部システムへ送信済みの記録と突き合わせて矛盾がないか(第13回の「同期できないデータの一覧」と同じ観点です)
訓練の最大の成果は、第12回・第13回と同じく手順の不足の発見です。そしてRTOの7工程の所要時間が、初めて数値で埋まります。第7回の実務テンプレートに残した「復元テストの周期」という空欄は、この3条件で埋めてください。
訓練の当日に開発チームへ何を依頼するか(動作確認の担当範囲と確認項目)は、第18回の開発者向けプレイブックに置きます。本記事では、依頼する項目があることだけを設計に含めます。
【実務テンプレート】RPO/RTO定義表・復旧ランブック・訓練記録
RPO/RTO定義表
行は復旧単位の数です。アプリケーションの数ではありません。列は8つ。
- 復旧単位名
- データの所在(PV/マネージドDB/オブジェクトストレージ)
- ティア
- ゾーン障害のRTOとRPO
- リージョン障害のRTOとRPO
- RPOを実現する方式
- 所有者(第2回のRACI)
- 最終訓練日と実測RTO
6列目が空欄の行は、その数値が検証されていません。この列を必須にすることが、この表の主眼です。「RPO 15分」とだけ書かれた行は願望ですが、「RPO 15分/デュアルリージョンのバケットとturbo replication」と書かれた行は設計です。
復旧ランブック(DR発動時)
第16回で決めたランブックの5項目を、DR用に読み替えます。3項目を足します。
- この状態は何を意味するか。影響範囲を1文で
- 影響の評価に使う指標とダッシュボード。見る順番まで固定する
- 打てる手と、それぞれの所要時間。訓練の実測値を書く
- エスカレーションの条件と連絡先。発動判断の会議を招集する条件を含む
- やってはいけないこと。過去に状況を悪化させた操作
- 戻せなくなる時点。この手順のどこから不可逆か
- 自動同期とバックアップ保存先の停止と再開。開始時と終了時の2箇所に明示する
- フェイルバックの起点。DRが終わった後に何を始めるか
保管先の要件も第16回のままです。監視対象と同じ障害範囲に置かないこと。加えて公開ステータスページのURLを書いておくこと。
DR訓練の記録
記入欄は7つです。
- 実施日
- シナリオ(何を失ったと仮定したか)
- 使用したバックアップの取得日時とKubernetesバージョン
- 7工程それぞれの所要時間
- 失敗した箇所と原因
- 手順書の修正点
- 次回実施予定日
4番目がこの記録の主眼です。ここが埋まって初めて、RTOが検証された数値になります。3番目にバージョンを書かせているのは、前述のAPIバージョンの窓を、訓練のたびに実地で確認するためです。
次回予告
本記事で決めたのは、リージョンが失われたときに使う数値と、その数値を満たす復旧の経路です。RPOとRTOを制約として扱い、保持の上限をAPIバージョンの窓から導き、復旧を順序の設計として組み立てました。
ここまでの17回は、すべて運用チームが読む設計書でした。次回の第18回「開発者向けオンボーディング・プレイブック」は、読む相手が変わります。連載の最終回です。第10回で引いた線をもう一度使います。インターフェースの設計は設計書、その使い方のガイドはプレイブック。17回ぶんの設計を、実際に使う開発チームへ渡す形式に変換します。
