- Authors

- Name
- Youngju Kim
- @fjvbn20031
- はじめに
- VirtualServiceからEnvoy RouteConfigurationへ
- DestinationRuleからEnvoy Cluster Configurationへ
- ロードバランシングアルゴリズム
- サーキットブレーカー実装
- リトライ実装
- フォールトインジェクション実装
- トラフィックミラーリング実装
- ServiceEntry:メッシュ拡張
- 高度なルーティングパターン
- デバッグツール
- まとめ
はじめに
Istioのトラフィック管理は試験範囲の40%を占めるほど中核的な領域です。この記事では、Istio CRDがどのようにEnvoy構成に変換され、Envoyが実際にトラフィックをどう処理するかの内部メカニズムを分析します。
VirtualServiceからEnvoy RouteConfigurationへ
変換パイプライン
VirtualService (Istio CRD)
│
▼ Pilot変換エンジン
Envoy Route Configuration
├── VirtualHost(ホストベースマッチング)
│ ├── Route(パス/ヘッダーマッチング)
│ │ ├── RouteAction(ルーティング先)
│ │ ├── WeightedCluster(重み付き分割)
│ │ └── RetryPolicy(リトライポリシー)
│ └── Route(デフォルトパス)
└── VirtualHost(他のホスト)
マッチ優先順位
VirtualServiceのHTTPマッチルールは定義順に評価されます。EnvoyのRouteConfigurationでも同じ順序が維持されます:
- 最も具体的なマッチが先(exact > prefix > regex)
- 複数のmatchブロックがある場合、最初のマッチが適用
- マッチ条件のないrouteはcatch-allとして動作
トラフィックシフティング
重み付きトラフィック分割の内部実装:
# Istio VirtualService
spec:
http:
- route:
- destination:
host: reviews
subset: v1
weight: 75
- destination:
host: reviews
subset: v2
weight: 25
これがEnvoyではWeightedClusterに変換されます:
{
"route": {
"weighted_clusters": {
"clusters": [
{
"name": "outbound|9080|v1|reviews.default.svc.cluster.local",
"weight": 75
},
{
"name": "outbound|9080|v2|reviews.default.svc.cluster.local",
"weight": 25
}
],
"total_weight": 100
}
}
}
Envoyは各リクエストごとに乱数を生成し、重み範囲に応じてクラスターを選択します。これは確率的分割なので、正確に75:25ではなく近似値で動作します。
DestinationRuleからEnvoy Cluster Configurationへ
Cluster構成変換
DestinationRuleはEnvoyのCluster構成に変換されます:
DestinationRule
├── host → Cluster名プレフィックス
├── subsets → 個別Cluster生成
│ ├── subset v1 → outbound|9080|v1|reviews.default.svc.cluster.local
│ └── subset v2 → outbound|9080|v2|reviews.default.svc.cluster.local
└── trafficPolicy → Clusterレベル設定
├── connectionPool → circuit_breakers
├── outlierDetection → outlier_detection
└── loadBalancer → lb_policy
Cluster命名規則
Envoy Clusterの名前は以下の形式に従います:
方向|ポート|サブセット|FQDN
例:
outbound|9080|v1|reviews.default.svc.cluster.local
inbound|8080||productpage.default.svc.cluster.local
ロードバランシングアルゴリズム
Round Robin(デフォルト)
リクエスト1 → Endpoint A
リクエスト2 → Endpoint B
リクエスト3 → Endpoint C
リクエスト4 → Endpoint A(循環)
Envoy実装:各エンドポイントに順番にリクエストを分配します。重みがある場合はWeighted Round Robinとして動作します。
Least Connections
Endpoint A: アクティブ接続3個
Endpoint B: アクティブ接続1個 ← 次のリクエストはここへ
Endpoint C: アクティブ接続5個
Envoy実装:O(1)演算で最も少ないアクティブリクエストを持つエンドポイントを選択します。
Random
各リクエストごとにランダムにエンドポイントを選択
大規模では統計的に均等分配
Consistent Hash
セッションアフィニティが必要な場合に使用します:
spec:
trafficPolicy:
loadBalancer:
consistentHashLB:
httpHeaderName: x-user-id
Envoy実装:Ketamaハッシュアルゴリズムベース。ハッシュリングにエンドポイントを配置し、リクエストキーをハッシュして最も近いエンドポイントを選択します。
ハッシュリング:
0 ─── EP_A ─── EP_B ─── EP_C ─── MAX
│ │
x-user-id:alice x-user-id:bob
(常にEP_A) (常にEP_B)
利点:
- エンドポイント追加/削除時の最小限の再マッピング
- 同じキーは常に同じエンドポイントへ(スティッキーセッション)
サーキットブレーカー実装
DestinationRule outlierDetectionからEnvoyへの変換
# Istio DestinationRule
spec:
trafficPolicy:
outlierDetection:
consecutive5xxErrors: 5
interval: 10s
baseEjectionTime: 30s
maxEjectionPercent: 50
Envoyでの動作:
{
"outlier_detection": {
"consecutive_5xx": 5,
"interval": "10s",
"base_ejection_time": "30s",
"max_ejection_percent": 50,
"enforcing_consecutive_5xx": 100
}
}
サーキットブレーカー状態マシン
[Closed] ──── 連続5xx >= 5 ────→ [Open/Ejected]
▲ │
│ baseEjectionTime経過
│ │
└──────── 成功リクエスト ──────── [Half-Open]
(リトライ)
詳細動作:
- Closed:正常状態。すべてのリクエストがエンドポイントに転送
- Open(Ejected):連続エラー閾値超過。エンドポイントがロードバランシングプールから除外
- Half-Open:baseEjectionTime後にエンドポイントがプールに復帰。再失敗時はejection時間が増加
接続プールベースのサーキットブレーカー
spec:
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
h2UpgradePolicy: DEFAULT
http1MaxPendingRequests: 1024
http2MaxRequests: 1024
maxRequestsPerConnection: 10
maxRetries: 3
Envoy内部動作:
リクエスト到着
│
▼
maxConnections (100) 超過? ──→ 503 (overflow)
│ No
▼
http1MaxPendingRequests (1024) 超過? ──→ 503 (overflow)
│ No
▼
http2MaxRequests (1024) 超過? ──→ 503 (overflow)
│ No
▼
リクエスト処理開始
│
maxRequestsPerConnection (10) 到達? ──→ 接続終了後新規接続
リトライ実装
VirtualService retriesからEnvoyへの変換
spec:
http:
- route:
- destination:
host: reviews
retries:
attempts: 3
perTryTimeout: 2s
retryOn: gateway-error,connect-failure,retriable-4xx
Envoyリトライポリシー:
{
"retry_policy": {
"retry_on": "gateway-error,connect-failure,retriable-4xx",
"num_retries": 3,
"per_try_timeout": "2s",
"retry_host_predicate": [
{
"name": "envoy.retry_host_predicates.previous_hosts"
}
]
}
}
リトライ動作詳細
元のリクエスト → Endpoint A(失敗、503)
│
リトライ1 → Endpoint B(失敗、503) ← previous_hostsでA回避
│
リトライ2 → Endpoint C(失敗、503) ← A、B回避
│
リトライ3 → Endpoint A(成功、200) ← 候補枯渇時は再利用
│
最終レスポンス:200
ポイント:
- previous_hosts:以前に失敗したホストを回避して別のエンドポイントにリトライ
- perTryTimeout:各試行ごとのタイムアウト(全体タイムアウトとは別)
- リトライバジェット:Envoy内部で同時リトライ数を制限
retryOn条件詳細
| 条件 | Envoy動作 |
|---|---|
| 5xx | アップストリームが5xxレスポンスを返した場合 |
| gateway-error | 502、503、504レスポンス時 |
| connect-failure | TCP接続失敗時 |
| retriable-4xx | 409(Conflict)など特定の4xx |
| refused-stream | アップストリームがREFUSED_STREAMエラーコードでストリームリセット時 |
| reset | レスポンスなしで接続がリセットされた場合 |
フォールトインジェクション実装
遅延注入(Delay Injection)
spec:
http:
- fault:
delay:
percentage:
value: 10
fixedDelay: 5s
route:
- destination:
host: reviews
Envoy実装:envoy.filters.http.faultフィルターがHTTPフィルターチェーンに挿入されます。
リクエスト到着
│
▼
Fault Filter:乱数生成(0-100)
│
├── 乱数 <= 10 → 5秒遅延後次のフィルターへ転送
│
└── 乱数 > 10 → 即座に次のフィルターへ転送
│
▼
Router Filter → アップストリームへ転送
中断注入(Abort Injection)
spec:
http:
- fault:
abort:
percentage:
value: 20
httpStatus: 503
route:
- destination:
host: reviews
Envoy実装:
リクエスト到着
│
▼
Fault Filter:乱数生成(0-100)
│
├── 乱数 <= 20 → 即座に503レスポンスを返却(アップストリームへリクエストしない)
│
└── 乱数 > 20 → 次のフィルターへ転送
複合フォールトインジェクション
遅延と中断を同時に適用できます:
spec:
http:
- fault:
delay:
percentage:
value: 50
fixedDelay: 3s
abort:
percentage:
value: 10
httpStatus: 500
評価順序:遅延が先に適用され、その後中断が評価されます。
トラフィックミラーリング実装
VirtualService mirrorからEnvoyへの変換
spec:
http:
- route:
- destination:
host: reviews
subset: v1
mirror:
host: reviews
subset: v2
mirrorPercentage:
value: 100
Envoy実装:
リクエスト到着
│
├── 元のリクエスト → reviews v1(レスポンスをクライアントに返却)
│
└── ミラーリクエスト → reviews v2(レスポンス無視、fire-and-forget)
│
└── Hostヘッダーに"-shadow"サフィックス追加
例:reviews → reviews-shadow
主な特徴:
- ミラーリクエストのレスポンスは完全に無視
- ミラーリクエストの失敗が元のリクエストに影響しない
- Hostヘッダーに"-shadow"が追加されてミラートラフィックを識別可能
ServiceEntry:メッシュ拡張
外部サービス登録
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: external-api
spec:
hosts:
- api.external-service.com
location: MESH_EXTERNAL
ports:
- number: 443
name: https
protocol: TLS
resolution: DNS
Envoyで生成されるリソース:
ServiceEntry
│
├── Listener: 0.0.0.0:443(アウトバウンド)にフィルターチェーン追加
│
├── Cluster: outbound|443||api.external-service.com
│ ├── type: STRICT_DNS
│ └── dns_lookup_family: V4_ONLY
│
└── Route: api.external-service.com → 該当Clusterにルーティング
Resolutionモード別動作
| Resolution | Envoy Cluster Type | 動作 |
|---|---|---|
| NONE | ORIGINAL_DST | 元のリクエストアドレスに転送 |
| STATIC | STATIC | endpointsフィールドのIPを直接使用 |
| DNS | STRICT_DNS | DNSで周期的に解決 |
| DNS_ROUND_ROBIN | LOGICAL_DNS | DNS結果の中から1つをラウンドロビン |
高度なルーティングパターン
ヘッダーベースのカナリアデプロイ
spec:
http:
- match:
- headers:
x-canary:
exact: 'true'
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
URIベースのルーティング
spec:
http:
- match:
- uri:
prefix: '/api/v2'
route:
- destination:
host: api-v2
- match:
- uri:
prefix: '/api'
route:
- destination:
host: api-v1
ソースベースのルーティング
spec:
http:
- match:
- sourceLabels:
app: frontend
version: v2
route:
- destination:
host: reviews
subset: v2
- route:
- destination:
host: reviews
subset: v1
デバッグツール
istioctlコマンド集
# VirtualService適用状態の確認
istioctl analyze -n NAMESPACE
# 特定サービスのルーティング構成確認
istioctl proxy-config routes PODNAME -o json | python3 -m json.tool
# Envoyのクラスター統計確認
istioctl proxy-config clusters PODNAME --fqdn reviews.default.svc.cluster.local
# サーキットブレーカー状態確認(Envoy管理ポート)
kubectl exec PODNAME -c istio-proxy -- curl -s localhost:15000/clusters | grep outlier
# リトライ統計
kubectl exec PODNAME -c istio-proxy -- curl -s localhost:15000/stats | grep retry
一般的な問題パターン
- 503 UC(Upstream Connection):アップストリーム接続失敗 - connectionPool設定を確認
- 503 UO(Upstream Overflow):サーキットブレーカートリガー - maxConnections/maxPendingRequestsを確認
- 503 NR(No Route):ルートマッチング失敗 - VirtualServiceのhost/matchを確認
- 503 UH(Upstream Unhealthy):すべてのエンドポイントがejected - outlierDetection設定を確認
まとめ
Istioのトラフィック管理エンジンは、結局Envoyの強力なプロキシ機能の上に構築されています。Istio CRDはユーザーフレンドリーな抽象化であり、実際の動作はEnvoyのリスナー、ルート、クラスター、エンドポイント構成によって決定されます。
トラフィック管理の問題をデバッグする際は、常に最終的にEnvoyに配信された構成を確認することが鍵です。istioctl proxy-configコマンドを習得すれば、ほとんどのトラフィック問題を迅速に診断できます。
次の記事では、Istioセキュリティモデルの内部実装を見ていきます。