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

Istioサービスメッシュ

重み・ヘッダ・ミラーリングでカナリアを転がす

TT Labで続きを見る

目標

重み・ヘッダー・ミラーリングの3つの分割方式を状況に合わせて選んで使い、元に戻す条件が明記されたカナリア計画を作れるようになります。

なぜ重要なのか

カナリアの本質は「少し流す」ことではなく、「いつ止めるかを先に決める」ことです。重みを上げる作業は誰にでもできますが、悪い指標を見て元に戻す判断を人に任せると、判断が揺らぎます。そこで、段階ごとに判断基準を書いておき、その基準がそのまま自動化の入力になるようにします。もう1つ大切なのは、Podの数とトラフィックの比率の分離です。メッシュでは、新バージョンをすべて起動しておいても、トラフィックは0%にしておけますし、問題が見えたら、デプロイなしで重みだけを0に戻せます。

このラボでは、2種類の採点が混ざっています。ステップ1・2・4・5は保存されたファイルを見て、ステップ6・7・8はクラスターに実際に適用された状態を見ます。そのため、ステップごとにファイルを別々に残す必要があります。1つのファイルを上書きし続けると、前のステップがもう一度失敗します。各vs-*.yamlファイルには、VirtualServiceのドキュメントを1つだけ入れてください(複数のドキュメントを1つのファイルに入れると、採点が最初のドキュメントを特定できません)。

ステップ

開始前の準備: ラボのPodはラボごとに新しく起動するため、前のラボのメッシュ設定は残っていません。kubectl get crd virtualservices.networking.istio.ioの結果が空なら、istioctl manifest generate --set profile=minimal > /root/istio/manifest.yamlを実行したあと、kubectl apply -f /root/istio/manifest.yamlを2回実行してください。そして、kubectl create ns mesh-lab && kubectl label ns mesh-lab istio-injection=enabledでネームスペースを作成してください。ステップ6では、起動中のPodをラベルで検索するので、フィクスチャのワークロードのPodがRunningになるまで待つ必要があります。

  1. まず/opt/lab/fixtures/istio/workload-v1v2.yamlをmesh-labに適用し、spec.subsetsにv1(labels: {version: v1})とv2(labels: {version: v2})を持つDestinationRule reviewsを適用しておいてください。そのあと、/root/istio/canary/vs-baseline.yamlを作成してください。VirtualServiceは1つで、spec.http[0].routeの項目はちょうど2つ、subset: v1のweightは100、subset: v2のweightは0です。
  2. /root/istio/canary/vs-90-10.yamlを作成してください。v1はweight: 90、v2はweight: 10です(合計は100)。このファイルをkubectl applyし、その出力を/root/istio/canary/out/applied-10.txtに保存してください(configured・created・unchangedのどれかが表示されている必要があります)。
  3. 重みの合計が100ではないファイル(例: /root/istio/canary/vs-bad.yamlにv1を90、v2を20)を作成してistioctl validate -fで検査し、その拒否メッセージを標準エラー出力も含めて/root/istio/canary/out/weight-error.txtに保存してください。そして、/root/istio/canary/out/weight-note.txtに、重みの合計は100でなければならないというルールを書いてください。
  4. /root/istio/canary/vs-header.yamlを作成してください。ヘッダーx-canaryがちょうどtrueであるリクエストを選ぶルートを前のほうに置き、宛先はsubset: v2、weight: 100です。その後ろに、条件のない既定ルートをもう1つ置いてください(条件付きルートが最後になってはいけません)。
  5. /root/istio/canary/vs-mirror.yamlを作成してください。spec.http[0].routeはsubset: v1のweight: 100で、同じ項目にmirror(host: reviews、subset: v2)とmirrorPercentage.value: 10を置いてください。そして、/root/istio/canary/out/mirror-note.txtに、ミラーされたリクエストの応答は捨てられることと、書き込み処理の副作用のリスクを書いてください。
  6. まずvs-90-10.yamlをもう一度適用して、v1とv2の両方を参照する状態にしてください。そのあと、DestinationRule reviewsのsubset名v2を一時的にv2-canaryに変えて適用し、istioctl analyze -n mesh-labの結果を/root/istio/canary/out/analyze-mismatch.txtに保存してください。名前をv2(labels version: v2)に戻して適用してから、もう一度分析して/root/istio/canary/out/analyze-clean.txtに保存してください(ここにはError [が含まれていてはいけません)。
  7. DestinationRule reviewsにtrafficPolicy.loadBalancer.consistentHash.httpHeaderName: x-user-idを追加して適用してください。そして、/root/istio/canary/out/sticky-note.txt(50バイト以上)に、同じユーザーがバージョンの間を行き来するとなぜ問題になるのかを書いてください。
  8. /root/istio/canary/rollout.yamlを作成してください。最上位にstages配列(5段階以上)とrollbackキーが必要です。各stageには、weight(v2の重み)とcriteria(次の段階へ進む判断基準)が両方必要で、weightは0で始まって100で終わり、途中で減ってはいけません。最後に、実際のVirtualService reviewsをv1が50、v2が50で適用してください(spec.httpの最後の項目が基準です)。istioctl analyze -n mesh-labの結果は/root/istio/canary/out/final-analyze.txtに保存し、エラーがあってはいけません。

参考

100/0の出発点マニフェストを作成する

まず/opt/lab/fixtures/istio/workload-v1v2.yamlをmesh-labに適用し、spec.subsetsにv1(labels: {version: v1})とv2(labels: {version: v2})を持つDestinationRule reviewsを適用しておいてください。そのあと、/root/istio/canary/vs-baseline.yamlを作成してください。VirtualServiceは1つで、spec.http[0].routeの項目はちょうど2つ、subset: v1のweightは100、subset: v2のweightは0です。

新バージョンをデプロイはするものの、トラフィックは流さない状態です。2つのsubsetをどちらも書いておけば、次のステップからは数字を変えるだけで済みます。

10%を新バージョンへ移す

/root/istio/canary/vs-90-10.yamlを作成してください。v1はweight: 90、v2はweight: 10です(合計は100)。このファイルをkubectl applyし、その出力を/root/istio/canary/out/applied-10.txtに保存してください(configured・created・unchangedのどれかが表示されている必要があります)。

前のステップのファイルを上書きせず、新しいファイルとして残してください。適用結果の出力も、証拠として保存する必要があります。

重みの合計が間違っているとどうなるかを確認する

重みの合計が100ではないファイル(例: /root/istio/canary/vs-bad.yamlにv1を90、v2を20)を作成してistioctl validate -fで検査し、その拒否メッセージを標準エラー出力も含めて/root/istio/canary/out/weight-error.txtに保存してください。そして、/root/istio/canary/out/weight-note.txtに、重みの合計は100でなければならないというルールを書いてください。

わざと間違ったファイルを作って、検証ツールに問い合わせてください。拒否メッセージそのものが、このステップの出力物です。コマンドが失敗で終わるため、標準エラー出力まで保存する必要があります。

このステップの核心は、何が検出され、何が検出されないかです。合計が110でも、現在のistioctlは通します。Envoyがtotal_weightで正規化するように変わったため、合計100というルールが検証から外れました。一方、合計が0なら拒否されます。両方を試して、結果を一緒に残してください。検証ツールがすべてのミスを見つけてくれるわけではない、というのがここで学ぶことです。

社内テスターだけを新バージョンへ送る

/root/istio/canary/vs-header.yamlを作成してください。ヘッダーx-canaryがちょうどtrueであるリクエストを選ぶルートを前のほうに置き、宛先はsubset: v2、weight: 100です。その後ろに、条件のない既定ルートをもう1つ置いてください(条件付きルートが最後になってはいけません)。

指定した人には、100%新バージョンを見せる必要があります。条件付きルートは既定経路より上に置き、既定経路は条件なしで一番最後に置きます。

応答を捨てるミラーリングを設定する

/root/istio/canary/vs-mirror.yamlを作成してください。spec.http[0].routeはsubset: v1のweight: 100で、同じ項目にmirror(host: reviews、subset: v2)とmirrorPercentage.value: 10を置いてください。そして、/root/istio/canary/out/mirror-note.txtに、ミラーされたリクエストの応答は捨てられることと、書き込み処理の副作用のリスクを書いてください。

ミラーリングは、ユーザーに返る応答を変えません。実際のトラフィックは従来のバージョンが100%処理し、コピーだけが新バージョンへ行きます。割合の指定も忘れないでください。

subsetとPodのラベルの不一致を作って直す

まずvs-90-10.yamlをもう一度適用して、v1とv2の両方を参照する状態にしてください。そのあと、DestinationRule reviewsのsubset名v2を一時的にv2-canaryに変えて適用し、istioctl analyze -n mesh-labの結果を/root/istio/canary/out/analyze-mismatch.txtに保存してください。名前をv2(labels version: v2)に戻して適用してから、もう一度分析して/root/istio/canary/out/analyze-clean.txtに保存してください(ここにはError [が含まれていてはいけません)。

ルートが参照するsubsetが定義から消えると、静的分析が検出します。ずれた状態と直した状態の分析結果を、それぞれ残してください。

同じユーザーを1つのバージョンに固定する

DestinationRule reviewsにtrafficPolicy.loadBalancer.consistentHash.httpHeaderName: x-user-idを追加して適用してください。そして、/root/istio/canary/out/sticky-note.txt(50バイト以上)に、同じユーザーがバージョンの間を行き来するとなぜ問題になるのかを書いてください。

重みによる分割は、リクエストごとにやり直して選びます。ロードバランサーをハッシュベースに変えて、どのヘッダーをキーにするかを決めてください。

段階別のカナリア計画を立てて中間まで進める

/root/istio/canary/rollout.yamlを作成してください。最上位にstages配列(5段階以上)とrollbackキーが必要です。各stageには、weight(v2の重み)とcriteria(次の段階へ進む判断基準)が両方必要で、weightは0で始まって100で終わり、途中で減ってはいけません。最後に、実際のVirtualService reviewsをv1が50、v2が50で適用してください(spec.httpの最後の項目が基準です)。istioctl analyze -n mesh-labの結果は/root/istio/canary/out/final-analyze.txtに保存し、エラーがあってはいけません。

計画には、段階ごとの重みと判断基準が必要で、全体には元に戻す方法が必要です。そして、実際のメッシュも中間の段階まで移しておいてください。