静的サブセットルーティングでは、すべての宛先ルール(DestinationRule)に各サブセットを明示的に列挙する必要があります。新しいバージョンがリリースされたり、古いバージョンが廃止されたりすると、誰かが手動でルールを更新する必要があります。動的サブセットルーティングはこのオーバーヘッドを解消します:Service Mesh(ASM)がワークロードのラベルを監視し、エンドポイントを自動的にサブセットにグループ化することで、手動変更なしにルーティングルールを常に最新の状態に保ちます。
以下のエンドツーエンドの例では、マルチバージョンアプリケーションをデプロイし、HTTP ヘッダーに基づいて特定のバージョンおよび環境にリクエストをルーティングしたうえで、ターゲットとなるサブセットが存在しない場合のフォールバック動作を設定します。
動的サブセットの仕組み
標準的な Istio ルーティングでは、宛先ルール(DestinationRule)が固定されたラベルセットで各サブセットを列挙します。バージョンが変更されると、その変更に合わせてルールを更新する必要があります。
動的サブセットは異なるアプローチを取ります。各サブセットを個別に列挙する代わりに、1 つ以上のグループ化キー(例:version および stage)を指定します。ASM はサービスの背後にあるすべてのエンドポイントのラベルを検査し、同じキーと値の組み合わせを持つエンドポイントを自動的に同一のサブセットにグループ化します。
その後、仮想サービス(VirtualService)が着信リクエストのヘッダーをこれらのグループ化キーにマップします。たとえば、x-version: v2 および x-stage: prod を含むリクエストは、version=v2 および stage=prod の条件を満たすサブセットにルーティングされます。
前提条件
開始する前に、以下の条件を満たしていることを確認してください。
v1.18 以降の ASM インスタンス
ACK クラスターの kubeconfig ファイルで構成済みの kubectl
ステップ 1:サンプルアプリケーションのデプロイ
この例では、hashicorp/http-echo を使用して、複数の環境およびバージョンにわたるデプロイメントをシミュレートします。
dev 環境:バージョン v1、v2、v3
prod 環境:バージョン v2、v3
各 Pod は、自身の環境、バージョン、および IP アドレスを応答として返します。helloworld サービス(ポート 8000)がすべての Pod をフロントエンドとして提供し、sleep デプロイメントがテスト用のクライアントとして機能します。

すべてのリソースを kubectl でデプロイします。詳細については、「ASM インスタンスに追加済みの ACK クラスターへのアプリケーションのデプロイ」をご参照ください。
ステップ 2:特定のバージョンおよび環境へのリクエストのルーティング
デプロイ後、Kubernetes はバージョンや環境に関係なく、すべての helloworld Pod 間でリクエストを負荷分散します。特定の組み合わせをターゲットにするには、グループ化キーを定義する宛先ルール(DestinationRule)と、リクエストヘッダーをこれらのキーにマップする仮想サービス(VirtualService)を作成します。
宛先ルールの作成
以下の宛先ルールを適用して、stage および version に基づいてエンドポイントをグループ化します。詳細については、「宛先ルールの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
namespace: default
spec:
host: helloworld.default.svc.cluster.local
trafficPolicy:
loadBalancer:
dynamicSubset:
subsetSelectors:
- fallbackPolicy: NO_FALLBACK
keys:
- stage
- versionASM は各エンドポイントの stage および version ラベルを読み取り、以下のサブセットを生成します。
| サブセット | Pod | IP アドレス |
|---|---|---|
| stage=dev, version=v1 | helloworld-dev-v1-67b6876778-nf7pz | 192.168.0.5 |
| stage=dev, version=v2 | helloworld-dev-v2-68f65bbc99-v957l | 192.168.0.1 |
| stage=dev, version=v3 | helloworld-dev-v3-7f6978bc56-hqzgg | 192.168.0.252 |
| stage=prod, version=v2 | helloworld-prod-v2-b5745b949-p8rc4 | 192.168.0.103 |
| stage=prod, version=v3 | helloworld-prod-v3-6768bf56f8-6bd6h | 192.168.0.104, 192.168.0.6 |
仮想サービスの作成
以下の仮想サービスを適用して、HTTP ヘッダーを動的サブセットキーにマップします。詳細については、「仮想サービスの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: helloworld
namespace: default
spec:
hosts:
- helloworld.default.svc.cluster.local
http:
- headerToDynamicSubsetKey:
- header: x-ip
key: '%ip%'
name: default
route:
- destination:
host: helloworld.default.svc.cluster.local
port:
number: 8000この仮想サービスは、以下の 2 つのマッピングを確立します。
x-versionヘッダーをversionグループ化キーにマップ。デフォルト:ヘッダーが存在しない場合の値はv3。x-stageヘッダーをstageグループ化キーにマップ。デフォルト:ヘッダーが存在しない場合の値はprod。
ルーティングの確認
dev 環境、バージョン v1 をターゲットとするリクエストを送信します。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: dev' -H 'x-version: v1' helloworld:8000期待される出力:
Welcome to helloworld stage: dev, version: v1, ip: 192.168.0.5このリクエストは、stage=dev および version=v1 の条件を満たす Pod に到達し、動的サブセットルーティングが正しく機能していることを確認できます。
ステップ 3:フォールバックポリシーの設定
v1 バージョンは prod 環境には存在しません。stage=prod, version=v1 をターゲットとするリクエストは、どのサブセットにも一致しません。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000一致しないサブセットを処理するには、宛先ルール(DestinationRule)に fallbackPolicy を設定します。ASM では、以下の 3 つのポリシーがサポートされています。
| ポリシー | 動作 | 推奨用途 |
|---|---|---|
NO_FALLBACK | no healthy upstream エラーを返します。これがデフォルトです。 | 誤ったルーティングに対して即座に失敗させる厳格なルーティング |
ANY_ENDPOINT | すべてのサブセットにわたる利用可能なエンドポイントのいずれかにルーティングします | 可用性が精度よりも重要となる開発またはテスト環境 |
DEFAULT_SUBSET(本番環境向け推奨) | 事前に設定されたデフォルトサブセットにルーティングします | 一致しないリクエストが既知の正常なバージョンにルーティングされるべき本番ワークロード |
NO_FALLBACK
NO_FALLBACK はデフォルトの動作です。一致するサブセットがないリクエストはエラーを返します。意図的に即時失敗させる場合は、明示的にこのポリシーを設定することを推奨します。
以下の宛先ルールを適用します。詳細については、「宛先ルールの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
namespace: default
spec:
host: helloworld.default.svc.cluster.local
trafficPolicy:
loadBalancer:
dynamicSubset:
subsetSelectors:
- fallbackPolicy: NO_FALLBACK
keys:
- stage
- version確認を行います。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000期待される出力:
no healthy upstreamANY_ENDPOINT
一致するサブセットがない場合、ラベルに関係なく、利用可能なエンドポイントのいずれかにリクエストがルーティングされます。
以下の宛先ルールを適用します。詳細については、「宛先ルールの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
namespace: default
spec:
host: helloworld.default.svc.cluster.local
trafficPolicy:
loadBalancer:
dynamicSubset:
subsetSelectors:
- fallbackPolicy: ANY_ENDPOINT
keys:
- stage
- version2 回のリクエストを送信して確認します。それぞれ異なる Pod に到達する可能性があります。
# 最初のリクエスト
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' helloworld:8000例の出力:
Welcome to helloworld stage: prod, version: v2, ip: 192.168.0.103# 2 回目のリクエスト — 存在しないサブセットをターゲット
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000例の出力:
Welcome to helloworld stage: dev, version: v2, ip: 192.168.0.1prod/v1 サブセットが存在しないため、リクエストはランダムなエンドポイントにフォールバックします。
DEFAULT_SUBSET
一致するサブセットがない場合、リクエストは defaultSubset で定義されたサブセットにルーティングされます。これは、一致しないリクエストが失敗したりランダムに分散したりするのではなく、既知の正常なバージョンに到達すべき本番ワークロード向けに推奨されるポリシーです。
以下の宛先ルールを適用します。この例では、defaultSubset が stage=prod, version=v3 を指しています。詳細については、「宛先ルールの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
namespace: default
spec:
host: helloworld.default.svc.cluster.local
trafficPolicy:
loadBalancer:
dynamicSubset:
defaultSubset:
stage: prod
version: v3
subsetSelectors:
- fallbackPolicy: DEFAULT_SUBSET
keys:
- stage
- versionprod/v1 という存在しないサブセットをターゲットとした 2 回のリクエストを送信して確認します。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000期待される出力:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-stage: prod' -H 'x-version: v1' helloworld:8000期待される出力:
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.104両方のリクエストは prod/v3 のデフォルトサブセットに到達します。2 つの異なる IP アドレス(192.168.0.6 および 192.168.0.104)は、2 つの prod-v3 レプリカ間での負荷分散を反映しています。
ステップ 4:IP アドレスによる特定の Pod へのルーティング
リクエストを個別の Pod に固定するには、組み込みの %ip% 属性をグループ化キーとして使用します。各 Pod は、単一メンバーのサブセットとなります。
宛先ルールの作成
以下の宛先ルールを適用して、Pod を IP アドレスでグループ化します。詳細については、「宛先ルールの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: helloworld
namespace: default
spec:
host: helloworld.default.svc.cluster.local
trafficPolicy:
loadBalancer:
dynamicSubset:
defaultSubset:
stage: prod
version: v3
subsetSelectors:
- keys:
- '%ip%'仮想サービスの作成
x-ip ヘッダーを %ip% キーにマップし、ヘッダーの値でターゲット Pod の IP アドレスを指定します。詳細については、「仮想サービスの管理」をご参照ください。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: helloworld
namespace: default
spec:
hosts:
- helloworld.default.svc.cluster.local
http:
- headerToDynamicSubsetKey:
- header: x-ip
key: '%ip%'
name: default
route:
- destination:
host: helloworld.default.svc.cluster.local
port:
number: 8000ルーティングの確認
Pod の IP アドレス 192.168.0.6 をターゲットとする複数のリクエストを送信します。
kubectl exec -it deploy/sleep -c sleep -- curl -H 'x-ip: 192.168.0.6' helloworld:8000期待される出力(繰り返し呼び出しでも一貫):
Welcome to helloworld stage: prod, version: v3, ip: 192.168.0.6すべてのリクエストが同一の Pod に到達し、IP ベースのピン留めが正しく機能していることを確認できます。
CRD フィールドリファレンス
仮想サービス(VirtualService)
HTTPRoute
ASM は HTTPRoute リソースを headerToDynamicSubsetKey フィールドで拡張しています。
| フィールド | 型 | 説明 |
|---|---|---|
headerToDynamicSubsetKey | HeaderToMetadataSubsetKey[] | リクエストヘッダーを動的サブセットのグループ化キーにマップします。各要素は 1 つのヘッダーからキーへのマッピングを定義します。 |
HeaderToMetadataSubsetKey
| フィールド | 型 | 説明 |
|---|---|---|
header | string | リクエストヘッダーの名前。 |
key | string | 動的サブセットのグループ化キーの名前。パーセント記号で囲まれた値(例:%ip%)は、組み込みのワークロード属性を参照します。 |
defaultValue | string | リクエストに指定されたヘッダーが存在しない場合に使用される値。省略されており、かつヘッダーが存在しない場合は、キーは未設定となり、サブセットマッチングから除外されます。 |
宛先ルール(DestinationRule)
ASM は trafficPolicy 構造体を dynamicSubset フィールドで拡張しています。
TrafficPolicy
| フィールド | 型 | 説明 |
|---|---|---|
dynamicSubset | DynamicSubsetLB | 動的サブセットのグループ化ルールを設定します。 |
DynamicSubsetLB
| フィールド | 型 | 説明 |
|---|---|---|
defaultSubset | map[string]string | fallbackPolicy が DEFAULT_SUBSET であり、リクエストに一致するサブセットがない場合に使用されるデフォルトサブセット。 |
subsetSelectors | SubsetSelector[] | グループ化ルールのリスト。各要素は独立したグループ化ディメンションを定義します。 |
fallbackPolicy | DynamicSubsetLB_FallbackPolicy | 一致するサブセットがない場合のグローバルフォールバックポリシー。デフォルトは NO_FALLBACK です。 |
SubsetSelector
| フィールド | 型 | 説明 |
|---|---|---|
keys | string[] | ワークロードラベルにマップされるグループ化ディメンション。たとえば、version は version ラベルに基づいてエンドポイントをグループ化します。%ip% などの組み込みワークロード属性もサポートされます。 |
fallbackPolicy | DynamicSubsetLB_FallbackPolicy | この特定のグループ化ルールに対するフォールバックポリシー。DynamicSubsetLB で設定されたポリシーを上書きします。 |
DynamicSubsetLB_FallbackPolicy
| 値 | 説明 |
|---|---|
NO_FALLBACK | 一致するサブセットがない場合にエラーを返します。これがデフォルトです。 |
ANY_ENDPOINT | 一致するサブセットがない場合に、サービスの任意のエンドポイントにルーティングします。 |
DEFAULT_SUBSET | 一致するサブセットがない場合に、defaultSubset で定義されたサブセットにルーティングします。 |
組み込みワークロード属性
| 属性 | 型 | 説明 |
|---|---|---|
%ip% | string | ワークロードが実行される Pod の IP アドレス。 |