TT Lab
はじめる
学ぶ 学習パス コース

KCA — Kyverno認定アソシエイト

Webhook障害実習:Fail・Ignoreと復旧

TT Labで続きを見る

目標

登録が残っているWebhookの応答だけを止めて、FailとIgnoreの違いを実際のリクエストで比べます。正常なサーバーの明示的な拒否、障害中のタイムアウト・保存、範囲外の対照群、復旧を、それぞれ確認します。

なぜ重要なのか

失敗という1つの言葉で、ポリシーの明示的な拒否とWebhook呼び出しのエラーをまとめると、対応を間違えます。ポリシー・登録・応答・すでに実行中のPodを、別々に観測する必要があります。2つのラボは、それぞれ新しいVMで始まり、ほかのラボの資料は必要ありません。受講生専用VMの外で障害を作らないでください。

正常なスケールダウンでは55秒の復旧監視プロセスを、応答の停止ではpidfdと20秒の自動再開タイマーを使います。このラボの想定時間は55分です。基本のセッションは60分なので、期限が切れる前に必要なら+時間で延長してください。最大は180分で、終了するとVMとファイルは消えます。必要な資料を先にダウンロードしてください。

すべての受講生のファイルは、/root/kca-webhookの下にあります。各act Nの生データはevidence/NN.jsonに保存され、内容はfactsから読み取ります。説明に出てくる02.jsonなどは、このevidenceのパスです。正規のJSONハッシュは、/opt/fixtures/kca_webhook_common.pyのdigest(read(パス))であり、sha256sumのファイルバイトのハッシュとは違います。Pythonでsys.pathに/opt/fixturesを追加して使ってください。

ステップ

  1. inspectで、このVMのvm.node_uidとnamespacesを確認してください。scope.jsonに、target=kca-webhook-target、control=kca-webhook-control、node_uid、namespacesを記録します。namespacesは、実際の名前をキー、UIDを値にします。act 1で、このVMの範囲を保存してください。
  2. policy.jsonに、policies.kyverno.io/v1のValidatingPolicyを書いてください。名前はkca-webhook-label、validationActions=[Deny]、failurePolicy=Fail、webhookConfiguration.timeoutSeconds=3、evaluation.background.enabled=falseです。matchConstraints.namespaceSelector.matchLabelsはkubernetes.io/metadata.name=kca-webhook-targetで、resourceRulesはapiGroups=[空文字列]、apiVersions=[v1]、operations=[CREATE]、resources=[pods]です。validationsのexpressionは"'environment' in object.metadata.?labels.orValue({})"、messageはKCA_ENVIRONMENT_REQUIREDです。不要なフィールドなしで書き、act 2で実際の登録を確認してください。
  3. act 3で、ラベルがあるPodの保存・UID・Runningと、ラベルがないPodの明示的な拒否・未保存を観測してください。evidence/03.jsonのfacts.good、bad、existingを比べます。前のラボのファイルやVMは持ち込みません。
  4. freeze-plan.jsonに、action=freeze-one-controller-process、実際のnode_uidとdeployment_uid、resume_after_sec=20、signal_identity=pidfd、preserve_webhook=true、evidence_sha256=03.jsonの正規のJSONハッシュを記録してください。act 4は、CRIコンテナ・Pod UID・PIDの開始時刻だけを調査し、まだ停止させません。
  5. act 5を実行してください。evidence/05.jsonで、登録の維持、停止区間の中の正常・違反リクエストのタイムアウトと未保存、範囲外の対照リクエストの保存、復旧後の違反の拒否と既存のPod UIDを、比べてください。明示的な拒否とcontext deadline exceededを区別します。
  6. policy.jsonをもとにpolicy-ignore.jsonを書き、spec.failurePolicyだけをIgnoreに変えてください。act 6は、同じポリシーUIDで、正常な違反の拒否を先に確認し、応答だけを短く停止します。evidence/06.jsonで、障害中の正常・違反リクエストの保存、復旧後の拒否、既存のPodの生存を、比べてください。
  7. recovery.jsonに、mode=Ignore、healthy_bad=explicit-deny、existing=same-uid-running、policy_uid=02.jsonのfacts.policy.metadata.uid、ignore_evidence_sha256=06.jsonの正規のJSONハッシュを入れてください。act 7は、新しい名前の違反リクエストを拒否し、ステップ3のベースラインPodの同じUID・Runningを確認します。
  8. report.jsonに、fail=matching-requests-timeout、ignore=unvalidated-request-stored、healthy_ignore=explicit-deny、control=outside-selector、existing=same-uid-runningを記録してください。fail_evidence_sha256、ignore_evidence_sha256、recovery_evidence_sha256は、それぞれ05・06・07.jsonの正規のJSONハッシュです。act 8のあと、全体の採点をもう一度実行してください。

参考

コマンドは、python3 /opt/fixtures/kca_webhook_lab.py inspect、act 1からact 8、grade 1からgrade 8です。gradeは、入力と保存された実際の観測を読み取り、障害を再び作りません。完了したactは、資料とリソースを保存します。部分的な入力も、自動では上書きしません。中断された実行は結果が不確実なので、失敗の生データをダウンロードして、新しいラボで再現してください。ポリシーの対象はCREATE podsです。すべてのAPI・すべてのインストールバージョン・高可用性に一般化しないでください。 Kubernetesサーバーdry-run

新しいVMで独立した実験の範囲

inspectで、このVMのvm.node_uidとnamespacesを確認してください。scope.jsonに、target=kca-webhook-target、control=kca-webhook-control、node_uid、namespacesを記録します。namespacesは、実際の名前をキー、UIDを値にします。act 1で、このVMの範囲を保存してください。

inspectのvm.node_uidとnamespacesを見てください。名前とUIDは違います。

Deny・Failのポリシーを直接書く

policy.jsonに、policies.kyverno.io/v1のValidatingPolicyを書いてください。名前はkca-webhook-label、validationActions=[Deny]、failurePolicy=Fail、webhookConfiguration.timeoutSeconds=3、evaluation.background.enabled=falseです。matchConstraints.namespaceSelector.matchLabelsはkubernetes.io/metadata.name=kca-webhook-targetで、resourceRulesはapiGroups=[空文字列]、apiVersions=[v1]、operations=[CREATE]、resources=[pods]です。validationsのexpressionは"'environment' in object.metadata.?labels.orValue({})"、messageはKCA_ENVIRONMENT_REQUIREDです。不要なフィールドなしで書き、act 2で実際の登録を確認してください。

namespaceSelectorは、namespaceのラベルを選びます。検証動作のDenyと、呼び出し失敗の処理であるFailを区別してください。

正常なサーバーの許可・拒否のベースライン

act 3で、ラベルがあるPodの保存・UID・Runningと、ラベルがないPodの明示的な拒否・未保存を観測してください。evidence/03.jsonのfacts.good、bad、existingを比べます。前のラボのファイルやVMは持ち込みません。

このVMのポリシーが最初から動作していてはじめて、あとの障害中の結果を解釈できます。

CRI・Pod・PIDの身元と、自動再開の計画

freeze-plan.jsonに、action=freeze-one-controller-process、実際のnode_uidとdeployment_uid、resume_after_sec=20、signal_identity=pidfd、preserve_webhook=true、evidence_sha256=03.jsonの正規のJSONハッシュを記録してください。act 4は、CRIコンテナ・Pod UID・PIDの開始時刻だけを調査し、まだ停止させません。

PIDの数字だけを信じると、再利用された別のプロセスを停止させてしまうことがあります。このラボではscale-downをしません。

登録を維持して、Failのタイムアウトを観測する

act 5を実行してください。evidence/05.jsonで、登録の維持、停止区間の中の正常・違反リクエストのタイムアウトと未保存、範囲外の対照リクエストの保存、復旧後の違反の拒否と既存のPod UIDを、比べてください。明示的な拒否とcontext deadline exceededを区別します。

正常なラベルのリクエストも止まるなら、検証式がFalseだからではなく、呼び出しに応答できなかったからかもしれません。

Ignoreの正常な拒否と、障害中の保存

policy.jsonをもとにpolicy-ignore.jsonを書き、spec.failurePolicyだけをIgnoreに変えてください。act 6は、同じポリシーUIDで、正常な違反の拒否を先に確認し、応答だけを短く停止します。evidence/06.jsonで、障害中の正常・違反リクエストの保存、復旧後の拒否、既存のPodの生存を、比べてください。

Ignoreは、ポリシーの無効化ではありません。正常な状態の明示的な拒否を先に確認してはじめて、障害中の保存を解釈できます。

復旧を、新しいリクエストと以前のUIDで再確認する

recovery.jsonに、mode=Ignore、healthy_bad=explicit-deny、existing=same-uid-running、policy_uid=02.jsonのfacts.policy.metadata.uid、ignore_evidence_sha256=06.jsonの正規のJSONハッシュを入れてください。act 7は、新しい名前の違反リクエストを拒否し、ステップ3のベースラインPodの同じUID・Runningを確認します。

プロセスに再開のシグナルを送ったという事実だけで、ポリシーの応答まで復旧したと結論づけないでください。

2つの障害の結果を根拠と結び付けたレポート

report.jsonに、fail=matching-requests-timeout、ignore=unvalidated-request-stored、healthy_ignore=explicit-deny、control=outside-selector、existing=same-uid-runningを記録してください。fail_evidence_sha256、ignore_evidence_sha256、recovery_evidence_sha256は、それぞれ05・06・07.jsonの正規のJSONハッシュです。act 8のあと、全体の採点をもう一度実行してください。

FailとIgnoreの違いを、正常な違反の判定ではなく、呼び出し失敗の処理として説明してください。Aのラボの資料なしに、このVMの観測だけで完成させます。