新しい機能が追加されたv2バージョンをユーザーにデプロイする必要がある状況を想像してみてください。🧐 もしすべてのトラフィックを一度にv2に送ったらどうなるでしょうか?予期せぬバグが発生した際、すべてのユーザーが影響を受けるという恐ろしい状況が発生する可能性があります。😱
このような問題を解決するために、私たちはカナリアデプロイメント(Canary Deployment)やブルー/グリーンデプロイメント(Blue/Green Deployment)のような戦略を使用します。特定のユーザーグループや一部のトラフィックだけを新バージョンに送り、安定性を検証するのです。
Kubernetes環境でサービスメッシュ(Service Mesh)の代表格であるIstioを使用すると、このプロセスを非常に優雅かつ強力に制御できます。今日はIstioがどのように特定のバージョンのサービスにトラフィックを送るのか、その核心概念を掘り下げてみましょう!

🤔 問題の始まり: Kubernetes Serviceの限界
まず、Kubernetesの基本的な動作を理解する必要があります。以下のようにmy-serviceという名前のServiceがあると仮定してみましょう。
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: my-app # 'app: my-app' ラベルを持つすべてのポッドを検索します。
ports:
- protocol: TCP
port: 80
targetPort: 8080
このServiceは、`app: my-app`ラベルを持つすべてのポッド(Pod)を自身のエンドポイントとします。もしv1バージョンのポッド3つとv2バージョンのポッド1つがすべて`app: my-app`ラベルを持っている場合、my-serviceに入ってきたリクエストは、これら4つのポッドに基本的にラウンドロビン(Round Robin)方式で分散されます。
- my-app Pods
- pod-v1-a (labels: app: my-app, version: v1)
- pod-v1-b (labels: app: my-app, version: v1)
- pod-v1-c (labels: app: my-app, version: v1)
- pod-v2-a (labels: app: my-app, version: v2) 🆕
この状況では、「v1にのみリクエストを送りたい」とか「全体のトラフィックの10%だけをv2に送りたい」といったきめ細やかな制御は不可能です。😥
✨ Istioの解決策デュオ: VirtualServiceとDestinationRule
このような限界を克服するために、IstioはVirtualServiceとDestinationRuleという2つの強力なCRD(Custom Resource Definition)を提供します。
- VirtualService (仮想サービス) 👮
- 役割: 「どこへ行くべきか?」トラフィックルーティングルールを定義します。
- 説明: my-serviceに入ってきたトラフィックを、どのような条件(ヘッダー、URI、ソースなど)に基づいてどこへ送るかを決定する交通警察のようなものです。例えば、「URIが`/api/v2`で始まる場合はv2サービスへ送る」とか「90%のトラフィックはv1へ、10%はv2へ送る」といったルールを定義します。
- DestinationRule (宛先ルール) 📖
- 役割: 「到達可能な場所はどこか?」実際の宛先(エンドポイントグループ)を定義します。
- 説明: VirtualServiceが道を教える前に、宛先がどのような特性を持っているかを定義した住所録のようなものです。ここで今日の主役であるサブセット(Subsets)が登場します。
この2つは常に一緒に動く必要があります。VirtualServiceがいくら「v2へ行け!」と叫んでも、DestinationRuleにv2という宛先グループが定義されていなければ意味がありません。
🎯 核心概念: DestinationRuleのサブセット(Subsets)
DestinationRuleの核心機能は、まさにサブセット(Subsets)を定義することです。サブセットは、特定のラベル(label)を基準にサービスのポッドを論理的なグループに分けることを意味します。
言葉よりもコードで見る方がはるかに理解しやすいでしょう。my-serviceに対するDestinationRuleを定義してみましょう。
DestinationRule Raw Data (YAML)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: my-service-dr
spec:
# このルールが適用されるサービスのホスト名
host: my-service.default.svc.cluster.local
# ポッドを論理的なグループに分けます。
subsets:
- name: v1 # このグループの名前は 'v1' です。
labels:
version: v1 # 'version: v1' ラベルを持つポッドのみがこのグループに属します。
- name: v2 # このグループの名前は 'v2' です。
labels:
version: v2 # 'version: v2' ラベルを持つポッドのみがこのグループに属します。
上記のYAMLファイルがすることは簡単です。
- hostフィールドを通じて、my-serviceにこのルールを適用すると宣言します。
- subsetsフィールド内に2つのグループを定義します。
- v1サブセット: `version: v1`ラベルを持つポッドの集まり 🏠
- v2サブセット: `version: v2`ラベルを持つポッドの集まり 🏡
これでIstioは、my-serviceが単に4つのポッドの束ではなく、v1とv2という名前の付いた2つの明確なグループで構成されていることを認識します。
🚀 サブセットの活用: VirtualServiceとの連携
DestinationRuleで住所録を作成したので、VirtualServiceという交通警察がこの住所録を見て道を案内する番です。
90%のトラフィックはv1へ、10%はv2へ送るカナリアデプロイメントの例
VirtualService Raw Data (YAML)
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: my-service-vs
spec:
hosts:
- my-service.default.svc.cluster.local # my-serviceに入ってくるすべてのトラフィックに対して
http:
- route:
- destination:
host: my-service.default.svc.cluster.local
subset: v1 # 'DestinationRule'で定義された 'v1' サブセットへ送る
weight: 90 # 重みは90%
- destination:
host: my-service.default.svc.cluster.local
subset: v2 # 'DestinationRule'で定義された 'v2' サブセットへ送る
weight: 10 # 重みは10%
VirtualServiceの`http.route`部分を見てください。`destination`に`subset`というフィールドがあります。ここにDestinationRuleで定義したサブセットの`name`(v1, v2)を正確に記載すると、Istioは該当ラベルを持つポッドグループにのみトラフィックを転送します。
このように2つのリソースを組み合わせることで、コードを一行も変更することなく、YAMLファイルの修正だけでサービスのトラフィックフローを完全に制御できるようになります。✨
❌ これはなぜ正解ではないのか?
Istioには様々なリソースがあり、混乱することがあります。他の概念とSubsetsの違いを明確に理解しましょう。
- ServiceEntry: サービスメッシュに含まれていない外部サービスをIstioが認識できるように登録するために使用されます。例えば、外部のクラウドデータベースAPIをメッシュ内部サービスのように呼び出したい場合に使用します。メッシュ内部サービスのバージョンを分割するのとは全く異なる目的を持ちます。
- Gateway: メッシュのエッジ(edge)で出入りするトラフィック(Ingress/Egress)を管理します。つまり、クラスター外部からのリクエストがどのように内部に入ってくるかを定義するゲートウェイの役割を果たします。一度入ってきたトラフィックを内部サービスバージョンごとにルーティングするSubsetsとは役割の位置が異なります。
- PodSelector: Kubernetesの基本概念で、特定のラベルを持つポッドを選択するために使用されます。DestinationRuleの`subsets`が内部的にラベルセレクターを使用するものの、Istio DestinationRule内で特定のバージョンのポッドグループを論理的に命名し定義するIstioの公式な概念はサブセット(Subsets)です。
💡 まとめ
サービス障害なしに安全に新バージョンをデプロイしたいなら、IstioのDestinationRuleとVirtualServiceを理解することは必須です。
- DestinationRuleは`subsets`を通じて、サービスのポッドを`version: v1`、`version: v2`のように意味のあるグループとして定義します。(住所録の作成 📖)
- VirtualServiceは、このように定義された`subsets`を宛先として使用し、トラフィックを重みに応じて分配したり、特定の条件に基づいてルーティングするルールを設定します。(交通整理 👮)
この2つの完璧な組み合わせを通じて、皆さんはどんな複雑なデプロイシナリオも自信を持って処理できる強力な武器を手に入れたことになります!
コメントを残す