デプロイゲートとプログレッシブデリバリの設計
目標
kustomizeのbaseと本番オーバーレイを作り、レンダリング結果にスキーマとポリシーのゲートをかけ、そのゲートが違反を実際に止めるかを確認します。そのあと、カナリアとブルー/グリーンをそれぞれどのServiceに付けるかを決めて、Rolloutに移します。
なぜ重要なのか
CNPEのGitOpsドメインは配点が25%で最も大きいです。そして、このドメインで実務と試験が一緒に求めるのは、ツールの使い方ではなく順序です。レンダリングが先で、検査がそのあとで、検査結果は必ず終了コードになる必要があります。この順序を守らないパイプラインは、緑ランプを出しながら何も守りません。
このラボのクラスターには、Argo CDコントローラーもArgo Rolloutsコントローラーもありません。CRDだけが登録されているので、マニフェストは本当に検証されて保存されますが、調整(reconcile)は起こりません。そのため、ここで学ぶのは「コントローラーが何をしてくれるか」ではなく、自分が何を宣言したかです。実際の試験でも、採点されるのは宣言です。
作業ディレクトリは/root/cnpe-deliveryで、本番ネームスペースはcnpe-prodです。
ステップ
/root/cnpe-delivery/baseにDeploymentcheckoutとServicecheckoutを作り、kustomization.yamlでまとめます。コンテナのポートとServiceのtargetPortは8080、replicasは1です。baseにはネームスペースを入れません。/root/cnpe-delivery/overlays/prodに本番オーバーレイを作ります。ネームスペースはcnpe-prod、replicasは4、イメージはダイジェスト(@sha256:の後ろの16進数64桁)で固定し、コンテナにrequestsとlimitsをどちらも入れ、runAsNonRoot: trueを設定します。/root/cnpe-delivery/policy/require-pinned.yamlにKyverno ClusterPolicyを書きます。validationFailureActionはEnforceで、Deploymentを対象に、(ア)イメージがダイジェストで固定されているか、(イ)すべてのコンテナにresources.limits.cpuとmemoryがあるか、の2つを検査します。/root/cnpe-delivery/gate.shを作ります。prodオーバーレイをレンダリングし、その結果にポリシーを適用して、違反があれば0以外のコードで終了する必要があります。どこから呼び出しても同じように動作するよう、スクリプトが最初に自分の場所へ移動するようにしてください。/root/cnpe-delivery/rollout/checkout-canary.yamlにカナリアRolloutcheckoutを書き、cnpe-prodに適用します。setWeightは10、30、60の順で、その間ごとにpauseを置き、最初のステップはsetWeightにする必要があります。canaryServiceとstableServiceは互いに異なるものにし、progressDeadlineSecondsは600以下にします。コンテナイメージは、prodのレンダリング結果のイメージと完全に同じである必要があります。/root/cnpe-delivery/argocd/application.yamlにArgo CD Applicationを書きます。projectはdefaultではない専用プロジェクト、source.pathはoverlays/prod、targetRevisionはHEADではない固定の参照にし、syncPolicy.automatedでpruneとselfHealを有効にして、syncOptionsにCreateNamespace=trueを入れます。destination.namespaceはレンダリング結果のネームスペースと同じである必要があります。/root/cnpe-delivery/rollout/ledger-bluegreen.yamlにAnalysisTemplateledger-smokeとブルー/グリーンRolloutledgerを書き、cnpe-prodに適用します。activeServiceとpreviewServiceは互いに異なり、autoPromotionEnabledはfalse、prePromotionAnalysisはledger-smokeを参照し、scaleDownDelaySecondsは300以上です。/root/cnpe-delivery/delivery-report.txtにprod_image、prod_replicas、canary_weights、auto_promotionの4行を키=값の形式(プレースホルダーはキーと値です)で書きます。値はすべて、レンダリング結果とクラスターから直接参照したものである必要があります。
参考
- レンダリング結果を読むときは、
kustomize build overlays/prod | yq -o=json -I=0 ea '[.]' | jq ...が便利です。 kyverno apply <정책> --resource <파일>(プレースホルダーはポリシーとファイルです)は、違反があれば終了コード1を返します。この値をそのままゲートの判断の根拠として使ってください。- カナリアの重みは、
kubectl get rollout checkout -n cnpe-prod -o jsonpath='{.spec.strategy.canary.steps[*].setWeight}'で数え直せます。 - よくある間違いの1つは、オーバーレイがbaseを絶対パスで指すことです。相対パスにしておけば、リポジトリごと移動してもレンダリングできます。
- もう1つは、ゲートを作って通ることだけを確認することです。わざと違反を入れて、赤ランプを一度見てください。
baseを作ってレンダリングできることを確認する
/root/cnpe-delivery/baseにDeploymentcheckoutとServicecheckoutを作り、kustomization.yamlでまとめます。コンテナのポートとServiceのtargetPortは8080、replicasは1です。baseにはネームスペースを入れません。
baseには環境に依存しない共通部分だけを入れます。ネームスペースや環境ごとのreplicasをここに入れると、オーバーレイがそれを上書きするせめぎ合いになります。レンダリングはkustomize buildで直接実行して確認してください。
本番オーバーレイが何を加えるか
/root/cnpe-delivery/overlays/prodに本番オーバーレイを作ります。ネームスペースはcnpe-prod、replicasは4、イメージはダイジェスト(@sha256:の後ろの16進数64桁)で固定し、コンテナにrequestsとlimitsをどちらも入れ、runAsNonRoot: trueを設定します。
kustomizeのimages項目には、newTagではなくdigestを使えます。replicasはreplicas項目で、リソースとセキュリティ設定はpatchesで重ねてください。確認はファイルではなく、kustomize buildの結果で行ってください。
ポリシーで何を止めるか決める
/root/cnpe-delivery/policy/require-pinned.yamlにKyverno ClusterPolicyを書きます。validationFailureActionはEnforceで、Deploymentを対象に、(ア)イメージがダイジェストで固定されているか、(イ)すべてのコンテナにresources.limits.cpuとmemoryがあるか、の2つを検査します。
Kyvernoのvalidate.patternで、*@sha256:*は部分一致、?*は「空でない値」を意味します。ポリシーが広すぎると正常なマニフェストまで止まるため、通るべきものと止まるべきものの両方をテストしてみてください。
ゲートが実際に止めるか確認する
/root/cnpe-delivery/gate.shを作ります。prodオーバーレイをレンダリングし、その結果にポリシーを適用して、違反があれば0以外のコードで終了する必要があります。どこから呼び出しても同じように動作するよう、スクリプトが最初に自分の場所へ移動するようにしてください。
ゲートの本体は検査ではなく、検査結果を終了コードに変換することです。そして、スクリプトがどこから呼び出されても同じように動作するには、最初の行で自分のディレクトリへ移動する必要があります。作ったあとは、わざと違反を入れて赤ランプを一度見てください。
カナリアに判断の場を作る
/root/cnpe-delivery/rollout/checkout-canary.yamlにカナリアRolloutcheckoutを書き、cnpe-prodに適用します。setWeightは10、30、60の順で、その間ごとにpauseを置き、最初のステップはsetWeightにする必要があります。canaryServiceとstableServiceは互いに異なるものにし、progressDeadlineSecondsは600以下にします。コンテナイメージは、prodのレンダリング結果のイメージと完全に同じである必要があります。
重みだけを並べると、少しゆっくりな全面デプロイです。重みの間ごとにpauseを置き、カナリアだけを別に観測できるようにServiceを分けてください。イメージはレンダリング結果からコピーしてくるほうが安全です。
同期の対象と宛先を固定する
/root/cnpe-delivery/argocd/application.yamlにArgo CD Applicationを書きます。projectはdefaultではない専用プロジェクト、source.pathはoverlays/prod、targetRevisionはHEADではない固定の参照にし、syncPolicy.automatedでpruneとselfHealを有効にして、syncOptionsにCreateNamespace=trueを入れます。destination.namespaceはレンダリング結果のネームスペースと同じである必要があります。
このPodにはArgo CDコントローラーがないため、同期の結果ではなく宣言を見ます。ただし、destination.namespaceはレンダリング結果のネームスペースと必ず同じである必要があります。2つの値がずれると、同期は成功するのに、どこにも反映されません。
書き込みを分けられないサービスの戦略
/root/cnpe-delivery/rollout/ledger-bluegreen.yamlにAnalysisTemplateledger-smokeとブルー/グリーンRolloutledgerを書き、cnpe-prodに適用します。activeServiceとpreviewServiceは互いに異なり、autoPromotionEnabledはfalse、prePromotionAnalysisはledger-smokeを参照し、scaleDownDelaySecondsは300以上です。
このステップは、ブルー/グリーンの宣言と分析テンプレートの参照を検査します。プレビュー用Serviceと手動プロモーションは、データの書き込みを遮断しません。実際の元帳では、単一writerの制御・スキーマの互換性・復旧を別に検証する必要があります。ここでは、参照した分析テンプレートも一緒に作り、activeServiceとpreviewServiceを区別してください。
デプロイの記録を値として残す
/root/cnpe-delivery/delivery-report.txtにprod_image、prod_replicas、canary_weights、auto_promotionの4行を키=값の形式(プレースホルダーはキーと値です)で書きます。値はすべて、レンダリング結果とクラスターから直接参照したものである必要があります。
4つの値とも、作り出さずに参照して書いてください。イメージとレプリカはレンダリング結果から、重みと自動プロモーションの有無はクラスターのRolloutから得られます。採点ツールが同じ値を再計算して突き合わせます。