削除事故をスナップショットで戻す
目標
実際にオブジェクトを削除したあと、スナップショットからよみがえらせます。復旧したデータディレクトリで2つ目のetcdを自分で起動し、「本当に戻ってきた」ことを目で確かめます。
なぜ重要なのか
復旧手順をドキュメントだけで知っていることと、一度やってみたことの差は大きいものです。特にsnapshot restoreがデータを巻き戻すコマンドではなく、新しいetcdクラスターを作るコマンドであるという事実は、自分の手でやってみて初めて身に付きます。だからこそ--name、--initial-cluster、--initial-advertise-peer-urls、--initial-cluster-tokenのようなアイデンティティ用のフラグを要求し、--data-dirには空の新しいパスを要求します。既存の/var/lib/etcdをそのまま指定した瞬間に、稼働中のデータに触れてしまいます。もう1つ重要なのが順序です。スナップショットをまず検証し、apiserverを止めて書き込みを止め、復旧し、マニフェストのhostPathを新しいパスに変え、最後にkubectlで確認します。この順序を逆にすると、使えないスナップショットでクラスターを立ち上げたり、復旧中に入った書き込みを失ったり、古いデータで再び起動したりすることになります。このラボでは、ライブクラスターを止めずに別のポートで復旧データを起動し、同じ結論にたどり着きます。
ステップ
- ネームスペース
etcd-labと、その中のConfigMapetcd-lab-marker(data.owner=platform)を作成してください。そのあと/root/etcd/restore/out/pre.jsonに、事故前の状態をJSONで記録してください。キーはmarker_owner(値はplatform)、registry_keys(/registryの下のキーの数、20以上)、revision(現在のetcdのrevision、0より大きい)の3つです。 - 復旧に使うスナップショットを
/root/etcd/restore/before.dbとして取り(20000バイト以上)、検証結果をJSONで/root/etcd/restore/out/before.jsonに保存してください。revisionが0より大きい必要があります。 - ConfigMap
etcd-lab-markerを削除して、事故を再現してください。削除後にそのオブジェクトを取得した出力を/root/etcd/restore/out/gone.txtに残してください。ファイルにはNotFoundまたはnot foundのような「存在しない」という応答が含まれている必要があり、ライブクラスターにこのConfigMapが再び作られていてはいけません。 before.dbを/root/etcd/restore/dataへ復旧してください。復旧後に/root/etcd/restore/data/member/snap/dbと/root/etcd/restore/data/member/walができている必要があります。復旧コマンドの出力(標準エラー出力を含む)を/root/etcd/restore/out/restore.txtに保存してください。- 今度はアイデンティティ用のフラグをすべて付けて、
/root/etcd/restore/data2へもう一度復旧してください。--data-dir、--name、--initial-cluster、--initial-advertise-peer-urls、--initial-cluster-tokenの5つのフラグがすべて含まれている必要があり、名前はrestored、ピアアドレスはhttp://127.0.0.1:12380、トークンはetcd-restore-labにしてください。実際に実行したコマンド全体を/root/etcd/restore/out/restore-cmd.txtにそのまま残してください(--data-dirに/var/lib/etcdを指定してはいけません)。 /root/etcd/restore/data2をデータディレクトリとする2つ目のetcdプロセスをバックグラウンドで起動してください。クライアントアドレスはhttp://127.0.0.1:12379、ピアアドレスはhttp://127.0.0.1:12380、名前はrestored、初期メンバーはrestored=http://127.0.0.1:12380、トークンはetcd-restore-labです。採点が終わるまでこのプロセスを終了しないでください。起動に使ったコマンドを/root/etcd/restore/out/second-etcd.txtに保存してください(ファイルに12379と--data-dirが見えている必要があります)。- 復旧データから
/registry/configmaps/etcd-lab/etcd-lab-markerキーを読み取り、値にplatformが含まれているか確認して、その出力を/root/etcd/restore/out/recovered.txtに保存してください。取得先は127.0.0.1:12379で、ライブクラスター(2379)にはこのオブジェクトが依然として存在しない必要があります。 /root/etcd/restore/runbook.mdに、復旧ランブックを400バイト以上で書いてください。各ステップは別々の行に置き、次の順序を守る必要があります。(1)スナップショットの検証(snapshot status)、(2)kube-apiserverの停止、(3)snapshot restore、(4)etcdマニフェストのhostPath/data-dirを新しいパスに置き換える、(5)kubectl getで確認。最後に、復旧が失敗した場合のロールバック方法も必ず書いてください。
参考
- スナップショットの検証と復旧は、
etcdutlが標準です。まずcommand -v etcdutlで確認し、あればetcdutl snapshot status/etcdutl snapshot restoreを使い、なければetcdctlの同じサブコマンドで代用してください(警告が付きますが動作します)。 - etcdサーバーの実行ファイルは別物です。まず
command -v etcdで探し、なければfind "$HOME/.kwok" -name etcd -type fで探してください(kwokctlがダウンロードしたバイナリがその下にあります)。バックグラウンド起動はnohup <etcd 경로> <플래그들> > /root/etcd/restore/out/second-etcd.log 2>&1 &の形が便利です。 - 2つ目のetcdのポートをライブのetcd(2379/2380)と重ねると、起動に失敗します。必ず12379/12380を使い、ステップ6と7を採点されるまでプロセスを生かしておいてください。
- 復旧ログと
kubectlのNotFoundメッセージは、すべて標準エラー出力に出ます。명령 > 파일 2>&1または명령 2>&1 | tee 파일で受け取らないと、ファイルに残りません。 - etcdに保存された値はprotobufなので、そのまま見ると文字化けして見えます。
| tr -d '\0'でヌルバイトだけを取り除くと、中に入っている文字列はそのまま読めます。 - よくある間違い1: ステップ8のランブックで
etcdctl snapshot restore --data-dir ...を1行に書いてしまうことです。そうするとsnapshot restoreとdata-dirが同じ行になり、順序の検査に引っかかります。複数行に分けるか、hostPathの置き換えを別の項目にしてください。同じ理由で、文書の前半でdata-dir、kubectl get、kube-apiserverをあらかじめ書かないでください。各単語の最初に現れた位置で順序を判定します。 - よくある間違い2: ステップ3でライブクラスターのConfigMapを再び作ってしまうことです。このラボの結論は「復旧データでだけよみがえる」です。
- ラボのPodはラボごとに新しく起動するので、前のラボで作った
etcd-labネームスペースとマーカーは残っていません。ステップ1で自分で作成してから始めてください。運用手順を記憶ではなくランブックとマニフェストとして残すべき理由が、まさにここにあります。
事故前の状態を数値で記録する
ネームスペースetcd-labと、その中のConfigMapetcd-lab-marker(data.owner=platform)を作成してください。そのあと/root/etcd/restore/out/pre.jsonに、事故前の状態をJSONで記録してください。キーはmarker_owner(値はplatform)、registry_keys(/registryの下のキーの数、20以上)、revision(現在のetcdのrevision、0より大きい)の3つです。
復旧は「何があったのか」を知ることから始まります。マーカーの値、/registryのキーの数、現在のrevisionの3つを1つのJSONにまとめてください。revisionはendpoint statusのヘッダーにあります。
復旧に使うスナップショットを確保して検証する
復旧に使うスナップショットを/root/etcd/restore/before.dbとして取り(20000バイト以上)、検証結果をJSONで/root/etcd/restore/out/before.jsonに保存してください。revisionが0より大きい必要があります。
復旧用のスナップショットは、取ったらすぐに検証します。事故が起きてからファイルが壊れていたと知っても、もう手遅れです。
削除事故を再現して痕跡を残す
ConfigMapetcd-lab-markerを削除して、事故を再現してください。削除後にそのオブジェクトを取得した出力を/root/etcd/restore/out/gone.txtに残してください。ファイルにはNotFoundまたはnot foundのような「存在しない」という応答が含まれている必要があり、ライブクラスターにこのConfigMapが再び作られていてはいけません。
オブジェクトを削除してから取得してみてください。存在しないリソースを取得したときのメッセージは標準エラー出力に出るので、リダイレクトに標準エラー出力も含めないとファイルに残りません。
スナップショットを新しいデータディレクトリへ復旧する
before.dbを/root/etcd/restore/dataへ復旧してください。復旧後に/root/etcd/restore/data/member/snap/dbと/root/etcd/restore/data/member/walができている必要があります。復旧コマンドの出力(標準エラー出力を含む)を/root/etcd/restore/out/restore.txtに保存してください。
復旧は既存のパスを上書きするのではなく、新しいパスを作る作業です。復旧ログも標準エラー出力に出ます。結果のディレクトリの中にmemberの構造ができているか確認してください。
クラスターのアイデンティティ用フラグを付けて復旧し直す
今度はアイデンティティ用のフラグをすべて付けて、/root/etcd/restore/data2へもう一度復旧してください。--data-dir、--name、--initial-cluster、--initial-advertise-peer-urls、--initial-cluster-tokenの5つのフラグがすべて含まれている必要があり、名前はrestored、ピアアドレスはhttp://127.0.0.1:12380、トークンはetcd-restore-labにしてください。実際に実行したコマンド全体を/root/etcd/restore/out/restore-cmd.txtにそのまま残してください(--data-dirに/var/lib/etcdを指定してはいけません)。
restoreは実は「新しいクラスターを1つ作る」コマンドです。名前、初期メンバー一覧、ピアアドレス、トークンの4つを明示すると、そのあとそのデータでetcdを起動できます。
復旧データで2つ目のetcdを起動する
/root/etcd/restore/data2をデータディレクトリとする2つ目のetcdプロセスをバックグラウンドで起動してください。クライアントアドレスはhttp://127.0.0.1:12379、ピアアドレスはhttp://127.0.0.1:12380、名前はrestored、初期メンバーはrestored=http://127.0.0.1:12380、トークンはetcd-restore-labです。採点が終わるまでこのプロセスを終了しないでください。起動に使ったコマンドを/root/etcd/restore/out/second-etcd.txtに保存してください(ファイルに12379と--data-dirが見えている必要があります)。
復旧したデータディレクトリを実際のプロセスに読み込ませて初めて、確認ができます。クライアントポートとピアポートをライブのetcdと重ならないようにし、採点が終わるまでプロセスを生かしておいてください。
削除したオブジェクトが復旧データに残っていることを確認する
復旧データから/registry/configmaps/etcd-lab/etcd-lab-markerキーを読み取り、値にplatformが含まれているか確認して、その出力を/root/etcd/restore/out/recovered.txtに保存してください。取得先は127.0.0.1:12379で、ライブクラスター(2379)にはこのオブジェクトが依然として存在しない必要があります。
Kubernetesのオブジェクトのetcdキーは/registry/<종류>/<네임스페이스>/<이름>です。値はprotobufなので人間には読みにくいですが、文字列はそのまま見えます。
復旧ランブックを書く
/root/etcd/restore/runbook.mdに、復旧ランブックを400バイト以上で書いてください。各ステップは別々の行に置き、次の順序を守る必要があります。(1)スナップショットの検証(snapshot status)、(2)kube-apiserverの停止、(3)snapshot restore、(4)etcdマニフェストのhostPath/data-dirを新しいパスに置き換える、(5)kubectl getで確認。最後に、復旧が失敗した場合のロールバック方法も必ず書いてください。
午前3時に読むドキュメントです。ステップの順序が重要で、失敗したときにどこへ戻るのかも書いておく必要があります。