ルーティング規則を設計する
目標
VirtualServiceとDestinationRuleの役割を手で切り分け、マッチルールの順序とAND/OR結合が、実際のルーティング結果をどう変えるかを身につけます。
なぜ重要なのか
ICAの出題比重の40%が、トラフィック管理です。ところが、この領域での実務の事故は、ほとんどが文法ではなく役割分担を知らないために生じます。「v2へ10%送る」ことはVirtualServiceが行いますが、「v2とは何か」はDestinationRuleが定義します。どちらか一方だけを作ると、Envoyの中には行き先のないルートや、誰も参照しないクラスターが残り、結果は503です。
ルールの順序も同じです。Istioは最初のマッチで評価を止めるので、包括的なルールを上に置くと、その下のルールは永遠に実行されません。逆に、最後にcatch-allがないと、予想外のリクエストがNRに落ちます。この2つは、コードレビューで捕まえるべき項目であり、そのためには目になじませておく必要があります。
このラボでは、Kubernetesの基本リソースは実際にapplyし、Istio CRDは/root/ica-traffic/の下にファイルとして作成します。ラボのクラスターにIstioのCRDがインストールされていないためであり、試験で求められる能力も「マニフェストを正確に書くこと」だからです。
ステップ
- ネームスペース
ica-trafficを作成し、ラベルistio-injection=enabledを付けてください。 - ネームスペース
ica-trafficに、Deploymentreviews-v1とreviews-v2を、それぞれレプリカ1つでデプロイしてください。2つのPodテンプレートはどちらもラベルapp=reviewsを持ち、reviews-v1はversion=v1を、reviews-v2はversion=v2を、追加で持つ必要があります。イメージはnginx:1.27-alpineを使ってください。 - 同じネームスペースにService
reviewsを作成してください。ポートは9080、ポート名はhttp、selectorはapp=reviewsだけを使います。 /root/ica-traffic/dr-reviews.yamlにDestinationRulereviewsを作成してください。spec.hostはreviews.ica-traffic.svc.cluster.local、subsetsはv1(labelsversion: v1)、v2(labelsversion: v2)の順です。/root/ica-traffic/vs-reviews-weight.yamlにVirtualServiceを作成してください。spec.hosts[0]はreviews.ica-traffic.svc.cluster.localで、httpルール1つにdestinationを2つ置き、subsetv1にweight 90、subsetv2にweight 10を指定します。/root/ica-traffic/vs-reviews-header.yamlにVirtualServiceを作成してください。ルールは2つです。最初のルールは、ヘッダーx-qa-userがtrueのリクエストをsubsetv2へ送り、2番目のルールは、matchなしでsubsetv1へ送ります。/root/ica-traffic/vs-reviews-rewrite.yamlにVirtualServiceを作成してください。uri.prefixが/api/v2/のリクエストのパスを/に書き換えて、subsetv2へ送ります。redirectは使わないでください。/root/ica-traffic/vs-reviews-final.yamlに、名前がreviews-finalのVirtualServiceを作成してください。ルール3つを順に置きます。(1)ヘッダーx-qa-user: trueならv2、(2)uri.prefixが/api/v2/で、かつmethod.exactがGETならv2、(3)matchのないcatch-allはv1。
参考
- マニフェストの骨組みは、
kubectl create deployment ... --dry-run=client -o yamlで出力して編集すると早いです。 - ファイルの文法の確認は、
yq '.spec' 파일명で行います(プレースホルダーはファイル名です)。値がnullと出たら、そのパスが間違っています。 - よくある間違い1: Serviceのselectorに
versionを入れて、1つのバージョンだけが対象になるようにしてしまうことです。そうすると、重みがまったく意味を持ちません。 - よくある間違い2: DestinationRuleのsubsetのラベルを、
v1のようなsubset名で書くことです。labelsはPodのラベルと同じである必要があります。 - ステップ8のAND条件は、matchの項目1つの中に
uriとmethodを並べて置く必要があります。項目を2つに分けると、ORになります。
メッシュに組み込むネームスペースを作成する
ネームスペースica-trafficを作成し、ラベルistio-injection=enabledを付けてください。
ネームスペースを作るだけでは、サイドカーは注入されません。自動注入を有効にするラベルをもう1つ付ける必要があります。ラベルのキーはistio-injectionです。
バージョンのラベルが異なる2つのDeploymentをデプロイする
ネームスペースica-trafficに、Deployment reviews-v1とreviews-v2を、それぞれレプリカ1つでデプロイしてください。2つのPodテンプレートはどちらもラベルapp=reviewsを持ち、reviews-v1はversion=v1を、reviews-v2はversion=v2を、追加で持つ必要があります。イメージはnginx:1.27-alpineを使ってください。
2つのDeploymentのPodが同じServiceにまとまるには、共通のラベル(app)が同じである必要があり、subsetで分かれるには、区別するラベル(version)が異なる必要があります。ラベルは、Podテンプレート側にあって初めて意味を持ちます。
2つのバージョンをまとめるServiceを作成する
同じネームスペースにService reviewsを作成してください。ポートは9080、ポート名はhttp、selectorはapp=reviewsだけを使います。
Serviceのselectorにversionを入れると、1つのバージョンだけが対象になり、重みによる分配ができなくなります。バージョンの区別は、Serviceではなく、DestinationRuleの役割です。ポート名も、プロトコルが分かるように付けてください。
subsetを定義する
/root/ica-traffic/dr-reviews.yamlにDestinationRule reviewsを作成してください。spec.hostはreviews.ica-traffic.svc.cluster.local、subsetsはv1(labels version: v1)、v2(labels version: v2)の順です。
subsetのlabelsは、Podのラベルと文字どおりに同じである必要があります。食い違うと、クラスターはできるのにエンドポイントが0個になり、503 UHに遭遇します。hostは、短い名前ではなくFQDNで書いてください。
90/10の重みによる分配
/root/ica-traffic/vs-reviews-weight.yamlにVirtualServiceを作成してください。spec.hosts[0]はreviews.ica-traffic.svc.cluster.localで、httpルール1つにdestinationを2つ置き、subset v1にweight 90、subset v2にweight 10を指定してください。
重みは、route配列の各destinationに付きます。合計が100になる必要があり、subset名は、ステップ4で作ったものと正確に同じである必要があります。
ヘッダーベースのルーティングとcatch-all
/root/ica-traffic/vs-reviews-header.yamlにVirtualServiceを作成してください。ルールは2つです。最初のルールは、ヘッダーx-qa-userがtrueのリクエストをsubset v2へ送り、2番目のルールは、matchなしでsubset v1へ送ってください。
ルールは上から下へ評価され、最初にマッチしたものが勝ちます。ヘッダー条件が付いたルールを先に、matchがまったくないルールを最後に置いてください。exactの値は文字列です。
URIプレフィックスの書き換え
/root/ica-traffic/vs-reviews-rewrite.yamlにVirtualServiceを作成してください。uri.prefixが/api/v2/のリクエストのパスを/に書き換えて、subset v2へ送ってください。redirectは使わないでください。
rewriteはリクエストをプロキシしながらパスを変え、redirectはクライアントに3xxを返します。このステップで必要なのは、バックエンドに気づかれないようにパスを変えるほうです。
3つのルールを1つのVirtualServiceにまとめる
/root/ica-traffic/vs-reviews-final.yamlに、名前がreviews-finalのVirtualServiceを作成してください。ルール3つを順に置いてください。(1)ヘッダーx-qa-user: trueならv2、(2)uri.prefixが/api/v2/で、かつmethod.exactがGETならv2、(3)matchのないcatch-allはv1。
最も具体的なルールが一番上、包括的なルールが一番下です。パスとメソッドをANDで結ぶには、matchの項目を2つ作らず、1つの項目の中に2つの条件を並べて置いてください。