配備を一つの変更ではなく十の層として見る

戻せる配備とは、以前のバージョンの実行ファイルを保管している状態ではありません。旧版と新版が一定期間、同じ設定とデータベーススキーマ、データ形式、外部契約をともに扱える必要があります。そのうえで機能の露出とトラフィックを個別に下げたり切ったりでき、どの信号が現れたら誰がどう動くかまで定まっている必要があります。

コードだけを旧版に戻したのに障害が広がることがあります。新しい配備がすでに列を削除したか、データを損失のある形へ変換しているかもしれません。機密情報が失効していたり、設定が新しい外部システムを向いていることもあります。新形式のメッセージがキューに溜まった後なら、旧コードはそれを読めません。こうした状況で旧バイナリを立ち上げ直すことは、復旧ではなくもう一つの非互換な変更です。

配備の道具は定められた行動を実行する装置にすぎません。KubernetesのDeploymentのリビジョンはPodテンプレートを中心に管理され、外部の設定やDB、データを一緒に戻すことはありません。[1] 進行が止まったDeploymentも状態を報告するだけで、その変更にロールバック・一時停止・前進修正のどれが正しいかは上位の運用体系が決めます。ですから配備前に書くべきは、今回どのコードが変わったかよりも、今回の変更がどの状態と契約を変えるかです。

Google SREは、成果物の再現性と自動化、設定の所有者とバージョンと意味の検証、漸進的な適用と停止の可否を、それぞれ別の運用条件として扱います。[6] 設定が実行のたびに変わる外部の値を追うなら、同じバージョンへ戻しても同じ状態は再現されません。

層
配備前に固定する契約
失敗時の第一手
互換性の撤去条件
責任者
コード・成果物同じソースと入力から識別可能な成果物を作り、ダイジェストとビルド来歴、以前の成果物を保存する検証済みの以前の成果物へトラフィックを戻すか、その複製を再び広げるロールバックの窓が閉じ、新しい成果物が安定と承認された後リリース責任者
依存関係ロックファイル、ベースイメージ、ランタイム、SDK、外部APIのバージョンを記録する以前の依存の束を使うか、互換アダプターを有効にする以前のランタイムやAPIを使う実行主体がなくなったときアプリケーション責任者
設定設定にバージョンと所有者を与え、形式だけでなく意味の検証も行う。変わりうる外部参照をそのまま追わせない以前の設定バージョンへ戻すか、設定の展開を止める旧・新のコードがともに新しい設定を正しく扱い、以前の参照が消えたときサービス・基盤責任者
機密情報機密情報のバージョンと有効な対象、交換順序、提供者障害時の動作を定める。安全上許される場合にだけ短い重複期間を置くまだ有効な機密情報へ切り替えるか、新しい機密情報を再配備する。漏えいしたものは復元しないすべての旧利用者が消え、新しい機密情報の利用が確認された後セキュリティ・基盤責任者
DBスキーマまず追加的な変更だけを行い、一定期間は旧・新のコードが同じスキーマで動くようにする旧コードを再び使いつつ、拡張したスキーマは保つ以前の列・表・制約を使うコードとジョブが完全になくなったときDB責任者
データ移行台帳、再実行の可否、中断と再開の条件、整合性検査と補償の方法を定める補填を止めてデータを是正するか前進修正する。必要なら隔離した復旧本からデータを再構成する補填・検証・照合が終わり、損失のない移行が確認された後データ・アプリケーション責任者
機能の露出フラグの既定値、提供者エラー時の値、伝播の遅れ、権限、監査記録を定義する。キルスイッチを実際に試験する機能の露出を切り、従来の動作へ迂回する機能が安定し、フラグがもはや復旧手段でなくなったときプロダクト・アプリケーション責任者
トラフィックバージョン別の経路と重み、セッションの固定、接続の整理、非同期トラフィックの帰属を記録する候補のトラフィックを0へ下げるか、以前の環境へ切り替える以前のバージョンへ戻る運用上の必要がなくなったときトラフィック・基盤責任者
健全性の信号候補と対照を区別する信号、観察期間、最小の証跡、行動を結びつける拡大の停止、フラグ切り、トラフィックの回収、ロールバック、前進修正のうち事前に定めた行動を実行する配備の評価が終わり、証跡と決定の記録が保存されたときサービス責任者・インシデント指揮者
責任者停止の権限、ロールバックの承認者、DB変更の責任者、トラフィックの実行者、手動の上書きと上位移管を明示する担当者のいない自動化は止める。インシデントモードへ移し、一つの意思決定権を立てる変更終了の記録と後続の責任が引き継がれたとき変更責任者
層別ロールバック契約 — 層ごとに契約・失敗時の第一手・撤去条件・責任者を書く

配備の状態を二つにすると何を失うか

配備のパイプラインを実行と成功または失敗の二状態にすると、途中でできることがロールバック一つだけになります。実際の運用には少なくともPrepared、部分的な露出、評価とベイクの三状態が要ります。評価の後には拡大・一時停止・ロールバック・前進修正の四つの分岐が開いている必要があります。

結果が良ければ拡大します。証跡が足りないか信号が汚染されていれば止めます。以前の状態との互換が生きているならロールバックが可能です。データや外部の状態がすでに不可逆に変わっているなら、修正版と補償作業を当てる前進修正のほうが適切です。カナリアは限定的な配備と評価手順を組み合わせたものであり、トラフィックを少なく送ったという事実だけでは足りません。[2]

ここで一時停止は重要な状態です。信号が不確かなのに自動で旧版を再配備すると、原因と無関係な二つ目の変更を作り、状況をさらに複雑にします。拡大を止めつつ現在の状態を保てば、比較と診断に必要な証跡を失いません。

Prepared
Preparedは成果物と設定、機密情報、スキーマの拡張、経路、観測の信号が整った状態です。以前のバージョンへ戻る経路もこの時点で検証します。
部分的な露出
部分的な露出は、新しいバージョンを限られた複製、利用者の集団、要求の比率、あるいは機能フラグの範囲にだけ見せる状態です。
評価とベイク
評価とベイクは時間が過ぎるのを待つ状態ではなく、候補と対照の差、非同期作業の完了、キャッシュとキューの影響が現れるまで観察する状態です。
サービスの仕組み

監視から復旧・改善までつながる運用 — サービス指標とアラートを基準に対応し、変更履歴と事後報告を次の改善につなげます。

互換性の維持期間は成果物の保管期間ではない

以前のバージョンへ戻れる期間は、単なる成果物の保管期間ではありません。旧コードが新しいスキーマと新しいデータを読み、新コードもまだ残る古いデータと要求を扱える期間です。

実務で互換性を保つべき期間は、七つの値のうち最も長いものより短くてはなりません。ロールバックの判断に要する時間、最も長く動くバッチとジョブ、キューとイベントの最大滞留時間、クライアント・セッション・キャッシュの寿命、データの補填と整合性検証の時間、機密情報の重複有効期間、複製の遅れと復旧検証の時間です。

これは特定の道具の公式ではなく、並行変更と漸進的な配備の原則を一つの運用の物差しにまとめた模型です。[3] 古いクライアントやキューのメッセージが残っているのに互換の列とアダプターを外せば、全トラフィックが新版へ移っていても配備はまだ終わっていません。

DBの変更は拡張・移行・縮小に分ける

互換性のないDB変更をコードの配備と同じ瞬間に実行すると、ロールバックの窓がほぼ即座に消えます。これを避ける代表的な方式が、拡張と移行、縮小に分けることです。customer_nameの列をdisplay_nameへ変えるとします。

拡張の段階では新しい列を足しつつ、既存の列を消しません。旧コードと新コードの双方が動くスキーマを先に作り、新しい列が空でも誤りが出ないよう読み取りの経路を設計します。移行の段階では、新しく生じるデータを必要な期間だけ二つの経路へ書くか、片方を台帳としつつもう片方を非同期で埋めます。既存のデータは小さな単位で補填しながら作業の位置と結果を記録します。中断して再開しても二重変換やデータの毀損があってはなりません。縮小の段階では、読み取りの経路が新しい列へ移り、旧版やバッチ、キューの消費者がもう既存の列を使わないという証跡を確かめたうえで、別の配備で既存の列を外します。「新コードが正常に配備された」と「以前の契約を外してよい」は別の決定です。[3]

DBエンジンによっても運用条件は変わります。PostgreSQLのALTER TABLEは、下位のコマンドによって強いロックを取るか表の再作成を起こします。[4][7] 定数の既定値の追加のように再作成を避けられる場合もありますが、条件を確かめる必要があります。マイグレーションのファイルが実行されるという事実と、運用中に安全だという事実は別なので、予想されるロックと再作成、実行時間、複製への影響を確認します。MySQLのアトミックDDLは障害時の一貫性を高める概念であり、利用者が任意に戻せるトランザクショナルDDLと同じではありません。[8]複数のDDLは暗黙のコミットを起こし、メタデータロックの影響を受けるため、アプリケーションのトランザクションと同じようにDDLを取り消せると仮定しません。

時点復旧も通常の配備のロールバックとは違います。PostgreSQLは基本バックアップとWALでクラスタ全体をある時点へ復旧し、設定ファイルは別の対象です。MySQLも全体バックアップとバイナリログの再生を組み合わせます。運用中のDBを過去の時点へ戻すと、目標時点以降の正常な変更まで影響を受けるため、まず隔離した復旧本から必要なデータを取り出し、現在の状態と照合する方式のほうが適切な場合が多いのです。[9]

不可逆なデータ変更は最初から印す

七種類の変更には完全な逆変換がないか、費用が過大です。複数の値を一つにまとめる損失のある集約、原本を捨てたうえでの暗号化と再符号化、重複したアカウントやレコードを一つに統合する作業、外部の決済・メール・メッセージ・Webhookの送信、すでに消費されたイベントと非同期のジョブ、復旧不能に廃棄した暗号鍵、新形式でだけ保存した後に消した原本の項目です。

この場合、ロールバック契約の行動は旧コードの再配備ではありません。新規の書き込みを止め、影響範囲を特定し、修正版を配備し、補償トランザクションかデータ修復を経て整合性を再検証する順になります。

不可逆かどうかが不明な変更は、配備メモで隠さずに「前進復旧が必要」とはっきり分類する必要があります。そうしてこそ、障害の最中に存在しない復旧経路を探して時間を失わずに済みます。

機能フラグとキルスイッチは同じ言葉ではない

機能フラグはバイナリの配備と利用者への露出を分けます。新しいコードを配備しつつ機能は隠したままにしたり、特定の利用者やテナント、地域にだけ開いたりできます。Google SREも機能フラグを、バイナリのリリースと機能の公開を分け、問題のある機能を選択的に切る手段として説明します。[2]

しかし、すべてのフラグが運用のキルスイッチであるわけではありません。安全なキルスイッチとして使うには七つの契約が要ります。フラグの提供者が応答しないときに使う安全な既定値、変更がすべてのインスタンスへ伝わる最大時間、利用者・テナント・地域ごとの適用範囲、変更の権限と監査記録、非常時に別の配備なしで操作できる経路、実際の運用条件を反映した切りの経路の試験、撤去の予定日と担当者です。

OpenFeatureはフラグ評価のAPIと提供者、評価コンテキスト、フック、提供者の状態イベントを標準化します。[5] 評価の誤りのときはアプリケーションが渡した既定値を返すと定義しますが、どの既定値が安全かと、フラグの変更がデータの副作用を戻せるかは、アプリケーション設計の責任です。すでに新形式のデータを書いたか外部へ要求を送った後なら、フラグを切ってもその状態は残ります。機能フラグは露出を止める制御装置であり、データの復旧装置ではありません。

ローリング・カナリア・ブルーグリーン・トラフィック分割の役割

四つの用語は互いに排他的な選択肢ではありません。カナリアを別のDeploymentとトラフィック分割で実装してもよく、ブルーグリーンの環境の間で一部のトラフィックだけを新環境へ送りながら評価してもかまいません。

Kubernetesのローリング更新では、置換の途中で旧いPodと新しいPodが同時に存在します。[1] Google SREはカナリアを、部分的で時間の限られた配備と評価の手順として定義し、代表的なトラフィックと測定の周期、共有依存の影響を併せて考えるよう求めます。[2] ブルーグリーンは経路の切り替えを速くしますが、DBと状態の契約まで自動で分けるわけではありません。

方式
何を変えるか
利点
隠れた互換性の条件
代表的な復旧行動
ローリング実行中のインスタンスを順に新しいバージョンへ置き換える追加の環境を大きく増やさずに漸進的な置換ができる旧・新が同時に動くため、DB・API・メッセージの契約が互換でなければならない展開の停止、以前の複製の拡大
カナリア一部のインスタンス・利用者・要求に候補を限られた時間だけ見せる影響範囲を絞り、候補と対照を比較できる標本に代表性が要り、共有のDB・キャッシュ・依存が対照まで汚染しうる露出の停止、トラフィックの回収、フラグ切り
ブルーグリーン以前の環境と新しい環境を並行して保ち、経路を切り替える以前の環境を残したまま新環境を検証し、経路を素早く戻せる共有DBやセッション、接続、機密情報、外部副作用が以前の環境でも扱えなければならない経路を以前の環境へ戻す
トラフィック分割ルーターやゲートウェイでバージョン別の要求比率を調整する比率だけでなく利用者・テナント・地域を基準に露出を制御できるセッションの固定、WebSocket、キューやバッチ、共有状態を別に扱う必要がある候補の重みを下げるか0にする
配備方式 — 四つの用語は排他的な選択肢ではなく重ねて使う道具である

ベイクタイムは固定の分単位ではない

ベイクタイムは「配備後30分待つ」のように定めておく休息の時間ではありません。今回の変更の主要な失敗が観測されるだけの代表的な作業が、実際に通り抜ける期間です。要求量と利用者の種類の多様さ、昼夜や平日・週末のトラフィックの型、最も長くかかるバッチと非同期のジョブ、キューの遅れと再試行の間隔、キャッシュとセッションの寿命、外部依存の呼び出し頻度、指標の集計周期と遅れ、データの補填と整合性検証の時間によって必要な長さが変わります。

トラフィックの少ないサービスでは、短いカナリアより合成の要求や明示的な検証の筋書きのほうが必要です。逆に要求量が多くても、候補と対照を分けない全体平均だけを見れば、候補の誤りが通常のトラフィックに隠れます。[2]

ロールバックの引き金は八つの項目で具体化する必要があります。すでに定義された利用者・サービスの健全性信号、候補と対照と全体のどこを見るか、候補と対照の許容差または絶対の遮断条件、その失敗が現れるのに要する観察期間、最小の要求とジョブと利用者集団、一時停止・フラグ切り・トラフィック0・ロールバック・前進修正のどの行動か、決定権者と実行者、手動の上書きの権限と理由の記録、失効の条件です。どの利用者導線をどの指標にするかは別の観測設計の領域であり、ここではすでに定義された健全性の信号を配備の行動へ結ぶところで止めます。

サービスの仕組み

サービス構成から運用基準まで — ネットワークとサーバーを設計し、デプロイ経路、アクセス権限、バックアップ基準を整えます。

自動ロールバックのほうが危うくなる場合

自動化が最初に取るべき行動は、常に旧版の再配備ではありません。八つの状況では自動の一時停止や露出の停止のほうが安全です。

Google SREはカナリアの評価で、候補と対照の汚染、観察期間、展開の停止と人の判断を併せて扱います。[2] Kubernetesも進行の失敗を状態として示しますが、復旧の行動を代わりに決めることはありません。[1] DBのロックと再作成、時点復旧の範囲まで考えれば、DBやデータ、機密情報、復元の経路を無条件に自動化するより、トラフィック拡大の停止を先に自動化するほうが安全な場合が多いのです。

状況
自動ロールバックの危険
より適切な第一手
候補が共有DBへ旧コードの読めないデータを書いた旧コードが同じデータを読み、さらに誤りを生む新規書き込みの停止、トラフィックの分離、前進修復
脆弱性を塞ぐため旧版と機密情報を失効させた旧版へ戻ることで脆弱性や失効済みの資格情報が蘇る修正版の配備、新しい機密情報の再発行
外部依存の障害が候補の誤りに見える原因と無関係な再配備が負荷と変数を増やす拡大の停止、候補と対照の比較
決済・メール・Webhookなどの外部副作用がすでに起きたコードだけが変わり、外の世界の状態は残る重複実行の遮断、補償作業
以前の環境のキャッシュが冷えているか容量が足りないトラフィックの復帰が新たな過負荷を生む漸進的なトラフィック回収、容量の確保
複数のカナリアや設定変更が同時に進んでいる信号の原因を切り分けられないまま繰り返しロールバックが起きるすべての拡大の停止、変更の分離
信号が短く揺れ、自動化が繰り返し動くバージョンが行き来する揺動と追加の障害が生じるクールダウン、手動承認、インシデントモード
以前の成果物と設定が実際には再検証されていない戻ってから初めて、以前の状態がすでに使えないと分かる以前の経路を点検してから手動で判断
自動ロールバックのほうが危うくなる八つの状況

ロールバック・前進復旧・フェイルオーバー・復元は別の行動だ

四つの行動は変える対象が違います。フェイルオーバーは実行の場所を変える行動で、復元はデータを再構成する行動です。ソフトウェアの欠陥がすべての環境へ配備されているなら、フェイルオーバーだけでは解決しません。データが毀損していないなら、全体の復元はむしろ正常なトランザクションまで過去へ戻します。[10]

ですから障害中はまず、いま何が壊れているかを問い、次に現在の互換性の契約がどこまで生きているかを確かめて、四つの行動から一つを選びます。

行動
変える対象
適する状況
データへの影響
主なリスク
ロールバックコード・設定・機能露出・トラフィックを以前の互換な状態へ戻す以前の状態との契約がまだ有効で、候補の影響が限定的なとき通常は現在のデータを保つが、旧コードがそれを扱えなければならないスキーマ・データ・機密情報が非互換なら失敗する
前進復旧修正コード、アダプター、マイグレーション、データ修復を新しいバージョンとして適用する状態変更が不可逆か、旧版が安全性・互換性の面で使えないとき現在の状態を保ちつつ、誤った部分を直す修正が十分に検証されなければ追加の変更リスク
フェイルオーバートラフィックや役割を正常な複製・リージョン・環境へ移す特定のインスタンス・ゾーン・リージョン、あるいは主系が使えないとき複製の状態と目標復旧時点により最新データに差が出る同じ欠陥版が移行先にもあれば問題は続く
復元バックアップ・スナップショット・WAL・バイナリログからデータの状態を再構成する削除や毀損、汚染で現在のデータ自体を信じられないとき目標時点以降の変更を失うか、別途の照合が要る長い復旧時間、正常な変更の喪失、依存システムとの不一致
ロールバック・前進復旧・フェイルオーバー・復元 — 四つの行動は変える対象が違う

配備前のロールバック準備点検

成果物と依存関係では五つを見ます。配備する成果物のダイジェストとビルド来歴が記録されているか、開発環境で作り直すのではなく検証済みの同一の成果物を昇格させているか、以前の成果物が実際に実行できる状態で保存されているか、ロックファイルとベースイメージ、ランタイム、主なSDKのバージョンを確認したか、外部API・メッセージ・イベントの契約の旧・新の互換を確認したかです。

設定と機密情報では六つを見ます。設定にバージョンと所有者があるか、形式の検査以外にエンドポイント・範囲・単位・排他の条件を含む意味の検証をしたか、実行のたびに変わる外部参照をそのまま追っていないか、機密情報の交換順序と以前の機密情報の有効終了の条件があるか、提供者の障害時の機能フラグと機密情報の参照の既定動作を確認したか、漏えいや失効した機密情報をロールバックの対象に使っていないかです。

DBスキーマとデータでは八つを見ます。破壊的な変更の前に追加的な拡張をしたか、旧版が拡張されたスキーマで読み書きできるか、マイグレーションが中断と再開と再実行に耐えるか、補填の進行位置と整合性検査の結果を記録しているか、二重書き込みを使うなら不一致の検出と照合の方法があるか、不可逆なデータ変更と外部副作用を別に印したか、ロールバックできない変更に前進復旧の手順があるか、DBエンジンとバージョンごとのロック・再作成・暗黙のコミットの条件を確認したかです。

機能の露出とトラフィックでは六つを見ます。バイナリの配備と機能の露出を分けられるか、キルスイッチの切りの経路を実際の運用条件で試験したか、候補と対照を区別する経路とラベルがあるか、トラフィックの重みを下げるか0にする権限と手順があるか、セッションと接続の整理、WebSocket、キューやバッチのトラフィックを考慮したか、以前の環境へトラフィックを戻すときに必要な容量を確認したかです。

信号と決定では六つを見ます。配備前にすでに定義した健全性の信号を候補基準で見られるか、ロールバックの引き金に観察期間と最小の証跡が含まれるか、一時停止・フラグ切り・トラフィック0・ロールバック・前進修正が区別されているか、自動の行動のクールダウンと手動の上書きがあるか、停止の権限者と実行の担当者が明示されているか、夜間や休日、担当者の不在時の上位移管の経路があるかです。最後に復旧の検証では、以前の成果物と設定へ実際に戻るリハーサルを行ったか、バックアップの有無とは別に復元の手順を試験したか、復旧の所要時間とデータ損失の範囲を記録したか、インシデント中の変更を一つに統制する責任者がいるか、配備と判定と上書きの記録を保存する場所があるかを見ます。

配備後の互換性撤去の点検

全トラフィックが新版へ移ったからといって、すぐに以前の契約を外しません。まず旧版へ向かう同期のトラフィックがないこと、古いクライアントやセッション、キャッシュがもう以前の契約を使わないこと、以前の形式のキュー・イベント・バッチの作業がすべて処理されたことを確かめます。補填が終わり原本と対象の整合を確認したか、二重書き込みの不一致がないか承認された許容の範囲内か、以前の列やAPI、メッセージスキーマの利用量が0か、以前の機密情報を使う消費者がいないかも併せて見ます。

その次が整理の作業です。ロールバックの窓の終了を変更記録に明示します。以前の機密情報の失効と権限の回収は別の変更として行います。機能フラグやアダプター、暫定の読み取り代替経路の撤去の担当者と日付を定めます。以前の列や表の削除は、切り替えと分けた別の配備で実行します。マイグレーションの後に新しいバックアップまたは復旧の基準点を確認したうえで、ランブックとスキーマ文書、依存の記録、運用の引き継ぎを更新します。撤去の作業そのものにも新しいロールバックと前進復旧の計画が要ります。

互換性のコードは技術的負債になります。とはいえ新版が正常だからという理由だけで同じ配備で外せば、最も重要な復旧の経路を自ら閉じることになります。追加・移行・撤去を別々の変更に分けてこそ、各段階の失敗の原因と復旧の行動も分かれます。

戻せる配備は配備の前に作られる

ロールバックのボタンは最後の実行装置です。そのボタンが安全であるためには、旧コードが新しいスキーマを扱えなければなりません。以前の環境が現在のトラフィックとセッションを受け、設定と機密情報の以前の状態がなお有効である必要があります。データの変更に逆変換がなければ、ボタンを押す前にすでにロールバックの選択肢は消えています。

運用中の最良の第一手は、時に旧版の再配備ではなく露出の拡大を止めることです。その次に現在の互換性の契約を確かめ、ロールバック・前進復旧・フェイルオーバー・復元から正しい行動を選びます。

DNSやキャッシュ、cron、DBの同期が一緒に変わるサーバー移設の作業にも、同じロールバック契約が要ります。ただし具体的な事前点検と切り替えの手順は、別の移行ランブックが扱います。