etcdの復元、データを戻してもKubernetesの監視がずれる理由

蛇腹状の紙と離れた二つのしおりで、保存内容と監視位置のずれを表した抽象画。

バックアップから保存データを戻せても、そのデータを見て動く仕組みまで、同じ時点へ戻るとは限りません。Kubernetesの復旧では、etcdに残る状態と、変更通知を受けてきたコントローラーの見ている状態が食い違うことがあります。

etcdは、キーと値の形で状態を保存する分散ストアです。変更の順序にはrevisionという番号を使います。ここではetcd v3.6の公式文書をもとに、スナップショットからの復元でこの番号が巻き戻る問題と、復元時に使う二つのオプションの役割を読み解きます。[1][2]

簡単にまとめると?

  • 古いスナップショットへ復元すると、保存データだけでなくrevisionも以前の値へ戻り、変更を監視する側のキャッシュが正しく更新されない場合があります。
  • --bump-revisionは番号を先へ進め、--mark-compactedは古い履歴からの監視を続けさせないための処置です。番号を増やしても、失われたデータは戻りません。
  • 復元後は、etcdが起動したことに加えて、監視の張り直しと利用側の状態の取り直しまで確かめる必要があります。

revisionは、時刻でも保存件数でもない

etcdのrevisionは、ストア全体に一つある、変更の順序を表す番号です。キーの集合が変更されると増え、どの更新が先だったかを並べる論理的な時計として使われます。複数の操作をまとめるトランザクションでは、その中で複数のキーを変更しても、revisionが増えるのは一度です。保存されているキーの数や、時計の秒数を表すものではありません。[2]

変更を受け取るwatchは、この番号を起点にできます。利用側が「ここまでは見た」と記憶しておけば、切断後にその続きの変更を受け取る仕組みを作れます。ただし、いつまでもすべての履歴が残るわけではありません。etcdは古いrevisionの履歴を保持しつつ、運用上の方針に従って整理するため、再開できる範囲には限りがあります。[2]

保存側だけを過去へ戻すと、観測の順序が崩れる

説明のため、revisionが1,000の時点でスナップショットを保存し、その後、利用側が1,400までの更新を観測したとします。障害後にそのスナップショットへ復元すると、etcd側の保存内容と番号は1,000の時点へ戻ります。一方、利用側には、1,400まで進んだという記憶や、その間に更新したキャッシュが残るかもしれません。これは仕組みを示す仮の数値です。

Kubernetesのコントローラーやオペレーターは、informerと呼ばれる仕組みで状態を手元に保持し、watchによる変更通知を利用することがあります。etcdの復旧文書は、古いrevisionへの復元によって、こうしたキャッシュが正しく更新されず、コントローラーの動作に不整合が生じ得ると指摘しています。保存側が応答できるようになったことだけでは、この不整合が解消したとは言えません。[1]

番号を進めることと、古い履歴を無効にすることを分ける

この問題に対し、公式文書が示すのがrevision bumpです。--bump-revisionには、復元するスナップショットのrevisionへ加える増分を指定します。到達させたい番号をそのまま指定するものではありません。先ほどの例なら、1,000に増分1,000を加えると、復元後の番号は2,000になります。ここでも数値は説明用であり、実環境に勧める設定値ではありません。[1]

ただし、番号が2,000になっても、保存内容が1,400の時点まで追いつくわけではありません。スナップショットに含まれない更新を作り直す処理ではなく、復元後の番号が利用側の観測済み番号より後になるようにする処置です。データの新しさと、通知の順序を示す番号を分けて見る必要があります。

もう一つの--mark-compactedは、増分を含むrevisionまでを、履歴の整理が済んだ範囲として扱います。etcdのWatch APIでは、整理済みのrevisionを起点とするwatchはキャンセルされます。同じ開始revisionのまま作り直しても失敗します。古い履歴を連続して読めるという前提を利用側へ残さず、キャッシュの無効化につなげるための処置です。[1][2]

二つの復元オプションの役割。etcd v3.6公式文書をもとにQuantum Seaが整理。
処置 変えるもの それだけでは行わないこと
--bump-revision スナップショットのrevisionに指定増分を加える。 スナップショット以後に失われた更新の復元。
--mark-compacted 増分を含むrevisionまでを整理済みとし、その古い履歴に基づくwatchを続けさせない。 独自クライアントのキャッシュ処理が正しく実装されていることの保証。

公式文書は、Kubernetesやwatchを利用するシステム、etcdデータのローカルコピーを持つシステムの復元では、revision bumpの利用を強く勧めています。Kubernetesのコントローラーについては、--mark-compactedも併用することが重要だと説明しています。番号を進めるだけの処置と、古い観測履歴を使えなくする処置は、同じ役割ではありません。[1]

増分は、スナップショットの古さと更新量に依存する

どれだけ番号を進めるかは、スナップショットの取得後に、どこまでrevisionが進んだ可能性があるかによります。公式文書には、毎秒1,500回未満の書き込みを仮定し、1週間前のスナップショットに10億を加える例があります。10億という値だけを抜き出すと、元の条件が抜けてしまいます。スナップショットがさらに古い環境や、更新量が多い環境でも十分だと保証する数字ではありません。[1]

検討時には、使うスナップショットのrevisionと取得時点、障害までの経過時間、更新の進み方を対応させます。また、revisionはキーの総数ではないので、保存件数が少ないことだけを根拠に、小さな増分でよいとは判断できません。同じキーを繰り返し変更する環境でも、番号は進むからです。[2]

戻すファイルの由来と、復元先の識別も別の確認点

監視の整合を考える前提として、どの状態を保存したファイルなのかも確かめます。公式文書は、稼働中のetcdからスナップショットを取得する方法と、データディレクトリ内のmember/snap/dbをコピーする方法を区別しています。後者では、先行して記録するWAL(write-ahead log)に含まれていても、まだdbへ書き込まれていないデータを失う可能性があります。[1]

整合性検査にも違いがあります。etcdctl snapshot saveで取得したスナップショットには、復元時に確認する整合性ハッシュが付きます。dbファイルを直接コピーした場合にはそのハッシュがなく、同じ検査はできません。検査を省けば同じ根拠が得られる、と読み替えないことが大切です。なお、ファイルの整合性が確認できても、必要な時点までの更新を含むことや、利用側のキャッシュまで一致することを一度に証明するものではありません。[1]

スナップショットからの復元では、member IDとcluster IDなどの識別情報も書き換えられ、新しい論理クラスタを作ります。元のクラスタへ誤って参加しないための扱いであり、単に保存ファイルを置き換えて同じクラスタの続きを動かす、という捉え方では不十分です。複数メンバーを復元するときは、同じスナップショットを使うことも公式文書の条件です。[1]

復旧確認を、保存側から利用側までつなぐ

復旧の検証では、戻ったキーと値、復元後のrevision、監視が古い履歴をそのまま使っていないかを、順につなげて確かめます。Kubernetesのコントローラーなら、手元の状態を取り直したあと、期待する対象を見て制御が再開したかまでを見る、という評価になります。これは公式文書の不整合の指摘から導く確認の考え方であり、すべての独自コントローラーの動作を保証するものではありません。

スナップショットは保存内容を以前の状態へ戻します。一方、その内容を見ていた利用側には、過去へ戻ったことを正しく受け止める経路が必要です。データを戻す処理、revisionを進める処理、古い監視履歴を無効にする処理を分けて理解すると、「etcdが起動した」から「制御が整合した状態で再開した」までの、確かめる範囲が見えてきます。

参考資料

2026年10月12日確認。etcd v3.6系列の公式文書に基づきます。

  1. etcd Authors — Disaster recovery。Revision Difference、Restoring with revision bump、Snapshotting the keyspace、Integrity Checks、Restoring from snapshot。
  2. etcd Authors — etcd API。Revisions、Transaction、Watch API/Watch streams。