By Ihyeok Song, STCLab SRE Team
STCLab では、トラフィック制御ソリューションである「NetFUNNEL」や、ボット対策プラットフォームの「BotManager」を SaaS として提供しています。数百万件の同時接続をリアルタイムで処理し、悪意のあるボットを瞬時に特定するためには、インフラに極めて高い安定性と柔軟性が求められます。私たちはその基盤として Istio を採用しています。
Istio には膨大な機能がありますが、本記事では実際のプロダクション環境で特に不可欠だった 5 つの機能に絞ってご紹介します。現在 Istio の導入を検討されている方や、具体的なユースケースを探している方のガイドになれば幸いです。
なぜ Istio なのか?
Istio は、コンテナと共にデプロイされた Envoy Proxy を管理するコントロールプレーンとして機能します。VirtualService、DestinationRule、AuthorizationPolicy といったすべての設定は、最終的に Envoy ネイティブの設定へと変換されます。
これが重要な理由は2つあります。
抽象化のメリット:Istio の抽象化された設定だけで、ほとんどのユースケースをエレガントに解決できる
柔軟な拡張性:標準機能で不十分な場合、EnvoyFilter を通じて Envoy の強力な機能に直接アクセスできる
私たちはインフラ全体で、この「シンプルさ」と「深さ」の両方を駆使しています。
1. Proxy Protocol による実クライアント IP の保持
課題
BotManager にとって、正確なクライアント IP は何よりも重要です。IP が正しくなければ、ボット検知の精度が著しく低下してしまうからです。
トラフィックが AWS の NLB (Network Load Balancer) を経由すると、元のクライアント IP が失われてしまう問題がありました。
解決策
私たちは EnvoyFilter を使い、Proxy Protocol でこの問題を解決しました。
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: botmanager-proxy-protocol
namespace: istio-ingress
spec:
workloadSelector:
labels:
scp: botmanager
configPatches:
- applyTo: LISTENER
patch:
operation: MERGE
value:
listener_filters:
- name: envoy.filters.listener.proxy_protocol
- name: envoy.filters.listener.tls_inspector
Tips
ソース IP の保持やネットワークトポロジ設定の詳細については、Istio 公式ブログの Configuring Gateway Network Topology を参照することを強くお勧めします。
また、セキュリティが重要な操作では X-Forwarded-For よりも X-Envoy-External-Address を優先しています。XFF とは異なり、このヘッダーは Envoy 自身によって設定され、外部クライアントによる偽装が不可能です。
2. IP ベースのアクセス制御(ホワイトリスト)
Swagger ドキュメントなどの内部 API を保護するため、AuthorizationPolicy を使用してアクセスをオフィス IP のみに制限しています。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: stclab-internal
spec:
action: DENY
selector:
matchLabels:
scp: netfunnel
rules:
- from:
- source:
notRemoteIpBlocks:
- 180.224.xxx.xxx/32 # Office IP
to:
- operation:
paths:
- /swagger/index.html
DENY アクションと notRemoteIpBlocks を組み合わせることで、「明示的に許可された IP 以外をすべて遮断する」というホワイトリスト形式のポリシーを、シンプルかつ効果的に構築できます。
3. クエリパラメータベースのルーティング
背景
NetFUNNEL は、待機列の状態をインメモリで管理しています。データの一貫性を保つため、各テナントのリクエストは常に同じバックエンドインスタンスに到達しなければなりません。
そこで、クエリパラメータを用いた明示的なルーティングを実装しました。
apiVersion: networking.istio.io/v1
kind: VirtualService
spec:
http:
- match:
- queryParams:
sticky:
exact: nf1
route:
- destination:
host: netfunnel-0 # First instance
- match:
- queryParams:
sticky:
exact: nf2
route:
- destination:
host: netfunnel-1 # Second instance
自動ハッシュではなく、このアプローチを採用した理由
アプリケーションチームと連携し、クライアントが sticky パラメータでターゲットインスタンスを直接指定するようにしました。これにより以下のメリットが得られます。
決定論的ルーティング:クライアントはどのインスタンスがリクエストを処理するかを正確に把握できる
デバッグの分離:問題のあるテナントを特定のインスタンスにルーティングして調査できる
スムーズな移行: メンテナンス中にテナントをインスタンス間で移動させやすい
代替案:Consistent Hash
厳密な一貫性を必要としないサービスには Consistent Hash を使用し、tenant_id に基づいて自動的に同じバックエンドへ振り分けています。
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: netfunnel-consistent-hash
spec:
host: netfunnel
trafficPolicy:
loadBalancer:
consistentHash:
httpQueryParameterName: tenant_id
コアサービスには「明示的ルーティング」、周辺サーっビスには「Consistent Hash」という使い分けが肝要です。
4. Outlier Detection による自動障害隔離
課題
大規模環境では、一つの不健全な Pod サービス全体の品質を低下させます。
解決策
私たちは Outlier Detection を使用して、異常なインスタンスを自動的に切り離しています。
outlierDetection:
consecutive5xxErrors: 5
interval: 10s
baseEjectionTime: 30s
maxEjectionPercent: 50
minHealthPercent: 30
動作の仕組み
検知:5 回連続で 5xx レスポンスを返した Pod を排出
隔離:排出された Pod は最低 30 秒間隔離
保護:可用性を守るため、Pod 全体の 50% 以上は同時に排出しない
実際の効果
先日、デプロイ時に一つの Pod がクラッシュループに陥りましたが、Outlier Detection が 50 秒以内にその Pod をローテーションから外しました。手動介入なしでトラフィックは健全な Pod にシフトし、サービスへの影響はゼロでした。
5. 長時間接続(Long-Lived Connections)のための Graceful Shutdown
課題
当社のゲートウェイは、10 分以上続くコネクションを処理します。デプロイ時にこれらを突然切断すると、テストが失敗します。
重要な設定ルール
terminationGracePeriodSeconds を terminationDrainDuration よりも長く設定する
apiVersion: apps/v1
kind: Deployment
metadata:
name: istio-ingress-loader
spec:
template:
metadata:
annotations:
proxy.istio.io/config: |
# Envoy drains connections for up to 10 minutes
terminationDrainDuration: 600s
proxyMetadata:
# Exit immediately when all connections are closed
EXIT_ON_ZERO_ACTIVE_CONNECTIONS: 'true'
spec:
# Kubernetes waits 11 minutes before force-killing
terminationGracePeriodSeconds: 660
info Checking for active connections...
info There are still 1316 active connections
info There are still 1308 active connections
info There are still 1300 active connections
info There are still 1292 active connections
info There are still 1279 active connections
info There are still 1276 active connections
warn Envoy proxy is NOT ready: server is terminated: received signal: terminated
info There are still 1269 active connections
info There are still 1257 active connections
info There are still 1252 active connections
info There are still 1247 active connections
info There are still 1242 active connections
info There are still 1235 active connections
info There are still 1229 active connections
info There are still 1228 active connections
info There are still 1223 active connections
info There are still 1220 active connections
info Checking for active connections...
info There are no more active connections. terminating proxy...
warn Aborting proxy
info Envoy aborted normally
warn Aborted proxy instance
info Agent has successfully terminated
シャットダウンシーケンス
-
Pod が終了シグナルを受信
-
Envoy が新規接続の受け入れを停止し、ヘルスチェックで失敗を返し始める
-
既存接続は terminationDrainDuration (600 秒) の間、維持される
-
EXIT_ON_ZERO_ACTIVE_CONNECTIONS により、接続が早く切れれば Pod も早期終了する
-
最終的に 660 秒後、Kubernetes が SIGKILL を送信
結果
デプロイ中のコネクションドロップがゼロ
ローリングアップデート中の負荷テストも正常に完了
プロダクション運用での知見
Istio をスケールさせる際のアドバイスをいくつか共有します。
1. シンプルに始める
初日からすべての機能を有効にしないでください。mTLS や Tracing のような複雑な機能は、ビジネス上の必要性が技術的コストを上回った時に導入すべきです。
2. メトリクスのカーディナリティに注意
Envoy は膨大なテレメトリデータを生成し、Prometheus をパンクさせることがあります。本当に必要なメトリクスだけを収集するようにフィルタリングしましょう。
3. EnvoyFilter は慎重に
強力ですが、Istio のアップグレード時に壊れやすい部分です。徹底したドキュメント化と互換性テストは不可欠です。
結論
Istio には学習曲線がありますが、NetFUNNEL や BotManager のような高トラフィックプラットフォームにおいて、それが提供する制御能力は投資に見合う価値があります。
本記事で紹介した5つの機能:
-
Proxy Protocol - 実クライアント IP の保持
-
AuthorizationPolicy - IP ベースのアクセス制御
-
柔軟なルーティング - クエリパラメータと Consistent Hash
-
Outlier Detection - 自動障害隔離
-
Graceful Shutdown - 長時間接続の安全な処理
これらは今や私のインフラの不可欠な要素です。トラフィック管理、セキュリティ、信頼性が重要なサービスを運用しているなら、Istio を検討する価値は十分にあります。