宣言と動作のあいだ
一言でいうと
Argoのオブジェクトは、意図を書いたものにすぎず、その意図を現実にするのはコントローラーです。コントローラーがなければ、YAMLが正しいかどうかさえわかりません。
なぜコントローラーが必要なのか
前のモジュールで、WorkflowとRolloutを何個も使いました。しかし、それらのラボが動く場所にはコントローラーがなかったため、そのYAMLが実際に何をするのかを確認する方法がありませんでした。
Argoの4つのプロジェクトは、すべてコントローラーがあってはじめて意味が生まれるものです。オブジェクトは、意図を書いたものにすぎず、その意図を現実にするのは、コントローラーです。
Workflows 컨테이너를 실제로 돌린다 없으면 단계가 진행되지도 실패하지도 않는다
Rollouts 파드를 실제로 띄우고 나눈다 없으면 카나리가 몇 퍼센트인지 볼 수 없다
Analysis Job 을 띄워 판정한다 없으면 자동 롤백이 통째로 빠진다
このコードブロックの韓国語は、Workflowsはコンテナを実際に実行し、なければステップが進行も失敗もしないこと、Rolloutsは、Podを実際に起動して分割し、なければカナリアが何%かを見られないこと、Analysisは、Jobを起動して判定し、なければ自動ロールバックが丸ごと抜け落ちることを述べています。
戻ったのはトラフィックであって、宣言ではない
最も価値のある落とし穴です。分析が失敗して自動ロールバックが起きても、spec.templateのイメージは、新しいバージョンのままです。
- そのままにしておくと、次に別のものを直してデプロイするときに、そのイメージも一緒に出ていきます
- GitOpsを使うと、リポジトリが依然として新しいイメージを指しているため、再び同じデプロイを試みます。無限に巻き戻るループになります
直すには、宣言を戻す必要があります。リポジトリのイメージタグを戻すコミットです。
limitはリトライの回数である
WorkflowsのretryStrategy.limitは、リトライの回数です。最初の試行はここに含まれません。limit: 2なら、実際の試行は3回です。
実行中にテンプレートを直しても変わらない
コントローラーが、開始時点の定義をstatus.storedTemplatesに埋め込んでおきます。再現性のためです。「テンプレートを直したのに、なぜそのままなのか」の答えがこれで、次のワークフローから変わります。
カナリアのウェイトが実際に何をするのか
setWeight: 20が、「リクエストの20%」を意味するのか、「Podの20%」を意味するのかは、構成によって異なります。この違いが、実測と期待をずらします。
| trafficRouting | ウェイトの意味 | 精度 |
|---|---|---|
| なし | Podの数の比率 | 粗いです。replicasが5なら、20%はPod1個です |
| Istio・Gateway API | 実際のリクエストの比率 | 正確です |
| NGINX Ingress | 実際のリクエストの比率(アノテーション) | 正確です |
trafficRoutingがないと、コントローラーはPodの数で近似します。replicas: 3でsetWeight: 10を指定すると、Pod0個は作れないため、1個(約33%)になります。小さなウェイトから始めるには、replicasが十分に大きいか、trafficRoutingがあることが必要です。
分析が何を見て判断するのか
AnalysisTemplateは、メトリクスのプロバイダーにクエリを投げて、その結果で続行するかを決めます。
metrics:
- name: error-rate
interval: 1m
count: 5 # 5번 재고
failureLimit: 2 # 2번 실패하면 롤백
successCondition: result[0] < 0.05
provider:
prometheus:
address: http://prometheus.monitoring.svc:9090
query: |
sum(rate(http_requests_total{status=~"5..",version="{{args.version}}"}[2m]))
/ sum(rate(http_requests_total{version="{{args.version}}"}[2m]))
このコードブロックの2つの韓国語コメントは、順に、5回計測することと、2回失敗したらロールバックすることを述べています。
ここでよく間違えるのが、カナリアだけを絞り込まないクエリです。上のクエリにversionラベルがないと、安定版とカナリアを合算して測ることになり、カナリアが100%失敗しても、全体のエラー率は20%しか上がりません。しきい値を超えず、悪いデプロイが通過します。
そして、トラフィックが少ないときの落とし穴があります。カナリアにリクエストが3個入ってきて、1個が失敗すると、エラー率は33%です。最小サンプル数の条件をあわせてかける必要があります。
successCondition: result[0] < 0.05 || result[1] < 20 # 요청이 20건 미만이면 통과
このコードブロックの韓国語コメントは、リクエストが20件未満なら通過させる、という意味です。
デプロイ戦略を選ぶ基準
| カナリア | ブルーグリーン | |
|---|---|---|
| リソース | 少し増える(段階ごと) | 2倍 |
| 巻き戻しの速度 | ウェイトを0にする。速い | Serviceセレクターの切り替え。最も速い |
| DBスキーマ | 2つのバージョンが長く共存 | 2つのバージョンが短時間共存 |
| 適した場所 | トラフィックが多く、メトリクスで判断できる | 検証を人が行う、またはトラフィックが少ない |
トラフィックが少ない内部サービスにカナリアを使うと、サンプルが足りず、分析が無意味です。その場合は、ブルーグリーンで、previewを人が確認して進めるほうがよいです。
実務で本当に大切なこと
自動ロールバックのあとには、必ず宣言を戻すコミットを入れます。ロールバックはトラフィックだけを戻し、spec.templateは新しいバージョンのまま残ります。GitOpsを使うと、リポジトリが依然として新しいイメージを指しているため、同じデプロイを無限に再試行します。
デプロイの判定は、Healthyではなく、status.stableRSで行います。昇格が終わってHealthyになったあとも、古いPodがTerminatingとして少しの間残り、イメージを数えると2種類が出ます。安定版を指すハッシュが、唯一ぶれない基準です。
retryStrategy.limitは、総試行回数ではありません。最初の試行はここに含まれないため、limit: 2は、実際には3回実行されます。タイムアウトの予算を計算するときに、1回ずつ見落とす場所です。
次の2つのラボで、これらを本物のコントローラーの上で、自分で確認します。