Skip to content
Published on

Istioアーキテクチャ内部分析:コントロールプレーンとデータプレーン

Authors

はじめに

IstioはKubernetes環境で最も広く使用されているサービスメッシュです。しかし「VirtualServiceを作成するとトラフィックがルーティングされる」というレベルを超えて、内部で実際に何が起きているかを理解することは、運用とトラブルシューティングに大きな違いをもたらします。

この記事では、Istioのコントロールプレーンとデータプレーンがどのように相互作用し、ユーザーが定義したCRDがどのようにEnvoy構成に変換されるかの内部メカニズムを分析します。

Istioアーキテクチャ概要

Istioは大きく2つの部分で構成されます:

┌─────────────────────────────────────────────────┐
Control Plane│  ┌───────────────────────────────────────────┐  │
│  │              istiod                        │  │
│  │  ┌─────────┐ ┌─────────┐ ┌──────────┐   │  │
│  │  │  Pilot  │ │ Citadel │ │  Galley  │   │  │
│  │    (xDS)  (CA)(Validate)│   │  │
│  │  └─────────┘ └─────────┘ └──────────┘   │  │
│  └───────────────────────────────────────────┘  │
├─────────────────────────────────────────────────┤
Data Plane│  ┌──────────┐  ┌──────────┐  ┌──────────┐     │
│  │ App + EP │  │ App + EP │  │ App + EP │     │
 (Pod A) (Pod B) (Pod C)  │     │
│  └──────────┘  └──────────┘  └──────────┘     │
EP = Envoy Proxy (istio-proxy sidecar)└─────────────────────────────────────────────────┘

istiod:統合コントロールプレーン

歴史的背景

Istio 1.5以前は、Pilot、Citadel、Galley、Mixerがそれぞれ別のマイクロサービスとしてデプロイされていました。Istio 1.5からistiodという単一バイナリに統合され、Mixerは1.8で完全に削除されました。

Pilot:トラフィック管理エンジン

PilotはistiodのコアでありI、以下の役割を果たします:

  1. サービスディスカバリ:Kubernetes APIサーバーを監視してService、Endpoint、Pod変更を追跡
  2. 構成変換:Istio CRD(VirtualService、DestinationRuleなど)をEnvoy構成に変換
  3. xDSサーバー:変換された構成をgRPCストリームで各Envoyプロキシにプッシュ
Kubernetes API Server
   ┌─────────┐
Pilot  │ ← Istio CRD監視 (VirtualService, DestinationRule, Gateway...)
   │         │ ← Kubernetesリソース監視 (Service, Endpoints, Pod...)
   └────┬────┘
xDS (gRPC stream)
   ┌─────────┐
Envoy  │ ← LDS, RDS, CDS, EDS, SDS受信
   └─────────┘

Citadel:証明書管理

Citadel(現在istiodに統合)はメッシュ内のワークロードアイデンティティと証明書を管理します:

  • **CA(Certificate Authority)**の役割を遂行
  • 各ワークロードにX.509証明書を発行
  • SPIFFE標準ベースのアイデンティティ付与
  • 証明書の自動ローテーション(デフォルト24時間)

Galley:構成検証

GalleyはIstio構成の妥当性を検証します:

  • Kubernetes Admission Webhookによる構成検証
  • CRDスキーマ検証
  • 構成間の参照整合性確認(例:VirtualServiceが参照するGatewayの存在確認)

Envoyサイドカー注入メカニズム

MutatingWebhookConfiguration

Istioのサイドカー注入はKubernetesのMutatingAdmissionWebhookを活用します:

apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
  name: istio-sidecar-injector
webhooks:
  - name: sidecar-injector.istio.io
    namespaceSelector:
      matchLabels:
        istio-injection: enabled
    rules:
      - apiGroups: ['']
        apiVersions: ['v1']
        operations: ['CREATE']
        resources: ['pods']

Podが作成される際、以下のプロセスが進行します:

1. kubectl apply -f deployment.yaml
2. Kubernetes API ServerがAdmission Webhookを呼び出し
3. istiodのSidecar InjectorがPodスペックを修正
4. 修正されたPodスペックが返却
5. 修正されたスペックでPodを作成

注入されるコンテナ

サイドカー注入時に2つのコンテナが追加されます:

1. istio-init(Initコンテナ)

initContainers:
  - name: istio-init
    image: proxyv2
    command:
      - istio-iptables
      - '-p'
      - '15001' # Envoy outboundポート
      - '-z'
      - '15006' # Envoy inboundポート
      - '-u'
      - '1337' # istio-proxy UID(このUIDのトラフィックはリダイレクト除外)
      - '-m'
      - 'REDIRECT'
    securityContext:
      capabilities:
        add: ['NET_ADMIN', 'NET_RAW']

istio-initコンテナはiptablesルールを設定して、すべてのインバウンド/アウトバウンドトラフィックをEnvoyプロキシにリダイレクトします。

2. istio-proxy(サイドカーコンテナ)

containers:
  - name: istio-proxy
    image: proxyv2
    ports:
      - containerPort: 15090 # Prometheusメトリクス
      - containerPort: 15021 # ヘルスチェック
    env:
      - name: ISTIO_META_CLUSTER_ID
        value: 'Kubernetes'
      - name: PILOT_CERT_PROVIDER
        value: 'istiod'

iptablesトラフィックリダイレクト

istio-initが設定するiptablesルールのフロー:

[インバウンドトラフィック]
外部 → Pod IP:Port
  → iptables PREROUTING
ISTIO_INBOUNDチェーン
REDIRECT to 15006 (Envoy inbound listener)
Envoyが処理後localhost:AppPortに転送

[アウトバウンドトラフィック]
App → 外部サービス IP:Port
  → iptables OUTPUT
ISTIO_OUTPUTチェーン
REDIRECT to 15001 (Envoy outbound listener)
Envoyが処理後実際の宛先に転送

[例外]
UID 1337 (istio-proxy)のトラフィックはリダイレクト除外 → 無限ループ防止

xDSプロトコル詳細

xDS(x Discovery Service)はEnvoyが動的に構成を受信するAPIプロトコルです。

xDS API種類

API正式名称役割
LDSListener Discovery Serviceリスナー構成(ポート、プロトコル)
RDSRoute Discovery ServiceHTTPルーティングルール
CDSCluster Discovery Serviceアップストリームクラスター定義
EDSEndpoint Discovery Serviceクラスター内の実際のエンドポイントリスト
SDSSecret Discovery ServiceTLS証明書とキー

構成プッシュフロー

[1] ユーザーがVirtualServiceを作成
[2] PilotがKubernetes API監視で変更を検知
[3] PilotがVirtualServiceをEnvoy RDS構成に変換
[4] 関連するCDSEDS構成も同時に生成
[5] gRPCストリームで該当ワークロードのEnvoyにプッシュ
[6] Envoyが新しい構成をホットリロード(接続切断なし)

ADS(Aggregated Discovery Service)

IstioはADSを使用してすべてのxDSレスポンスを単一のgRPCストリームに統合します。これにより構成の一貫性が保証されます:

  • CDSとEDS間の順序保証(クラスター定義が先、エンドポイントが後)
  • LDSとRDS間の順序保証
  • アトミックな構成更新

構成の確認方法

# 特定PodのEnvoyリスナー確認
istioctl proxy-config listeners PODNAME.NAMESPACE

# ルート構成確認
istioctl proxy-config routes PODNAME.NAMESPACE

# クラスター構成確認
istioctl proxy-config clusters PODNAME.NAMESPACE

# エンドポイント確認
istioctl proxy-config endpoints PODNAME.NAMESPACE

# 全Envoy構成ダンプ
istioctl proxy-config all PODNAME.NAMESPACE -o json

Envoyフィルターチェーンアーキテクチャ

Envoyプロキシは階層的なフィルターチェーンでリクエストを処理します:

[リクエストフロー]

Listener(ポートバインディング)
Filter Chain(一致するフィルターチェーンを選択)
    ├── Network Filters
    │   ├── TCP Proxy Filter (L4)
    │   └── HTTP Connection Manager (L7)
    │       │
    │       ├── HTTP Filters
    │       │   ├── RBAC Filter(認可)
    │       │   ├── JWT Authn Filter(認証)
    │       │   ├── Fault Injection Filter
    │       │   ├── CORS Filter
    │       │   ├── Stats Filter(メトリクス)
    │       │   └── Router Filter(最終ルーティング)
    │       │
    │       └── Route Configuration
    │           ├── Virtual Host選択
    │           └── Routeマッチングとクラスター決定
Cluster(アップストリーム選択)
Endpoint(実際の宛先Pod)

リスナー構造

Listener 0.0.0.0:15006 (Inbound)
├── FilterChain: Appポート(例:8080│   ├── TLS Inspector
│   ├── HTTP Connection Manager
│   │   ├── istio_authn filter
│   │   ├── envoy.filters.http.rbac
│   │   └── envoy.filters.http.router
│   └── Route: inbound|8080|http|service.ns.svc.cluster.local
└── FilterChain: Default (passthrough)

Listener 0.0.0.0:15001 (Outbound)
├── FilterChain: サービス別マッチング
│   ├── HTTP Connection Manager
│   │   ├── envoy.filters.http.fault
│   │   ├── envoy.filters.http.cors
│   │   ├── istio.stats
│   │   └── envoy.filters.http.router
│   └── Route: サービス別VirtualHost
└── FilterChain: PassthroughCluster(マッチしないトラフィック)

ワークロードアイデンティティ:SPIFFE

SPIFFE IDスキーム

IstioはSPIFFE(Secure Production Identity Framework For Everyone)標準を使用します:

spiffe://TRUST_DOMAIN/ns/NAMESPACE/sa/SERVICE_ACCOUNT

例:
spiffe://cluster.local/ns/production/sa/frontend

証明書発行フロー(CSR Flow)

[1] istio-agent(Pod内)が鍵ペアを生成
[2] CSR(Certificate Signing Request)を作成
[3] CSRをistiodに送信(gRPC、ブートストラップトークンで認証済み)
[4] istiodがCSRを検証:
    - ServiceAccountトークンの妥当性
    - ネームスペース所属の確認
[5] istiodのCAX.509証明書に署名
[6] 署名済み証明書をistio-agentに返却
[7] istio-agentがSDSを通じてEnvoyに証明書を配信
[8] EnvoyがmTLSに証明書を使用

SDS(Secret Discovery Service)

証明書はファイルシステムではなくSDSを通じてEnvoyに配信されます:

  • istio-agentがローカルSDSサーバーの役割を担当
  • EnvoyがSDS APIで証明書をリクエスト
  • 証明書ローテーション時にEnvoyの再起動不要
  • 証明書がディスクに書き込まれないためセキュリティが向上

構成変換:Istio CRDからEnvoy構成へ

VirtualService変換例

ユーザーが定義したVirtualService:

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: reviews-route
spec:
  hosts:
    - reviews
  http:
    - match:
        - headers:
            end-user:
              exact: jason
      route:
        - destination:
            host: reviews
            subset: v2
    - route:
        - destination:
            host: reviews
            subset: v1

これがEnvoy RDS構成に変換されます:

{
  "name": "reviews.default.svc.cluster.local:9080",
  "virtual_hosts": [
    {
      "name": "reviews.default.svc.cluster.local:9080",
      "domains": ["reviews.default.svc.cluster.local"],
      "routes": [
        {
          "match": {
            "prefix": "/",
            "headers": [
              {
                "name": "end-user",
                "string_match": {
                  "exact": "jason"
                }
              }
            ]
          },
          "route": {
            "cluster": "outbound|9080|v2|reviews.default.svc.cluster.local"
          }
        },
        {
          "match": {
            "prefix": "/"
          },
          "route": {
            "cluster": "outbound|9080|v1|reviews.default.svc.cluster.local"
          }
        }
      ]
    }
  ]
}

DestinationRule変換例

apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: reviews-destination
spec:
  host: reviews
  subsets:
    - name: v1
      labels:
        version: v1
    - name: v2
      labels:
        version: v2
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 100

これがEnvoy CDS構成に変換されます:

{
  "name": "outbound|9080|v1|reviews.default.svc.cluster.local",
  "type": "EDS",
  "eds_cluster_config": {
    "service_name": "outbound|9080|v1|reviews.default.svc.cluster.local"
  },
  "circuit_breakers": {
    "thresholds": [
      {
        "max_connections": 100
      }
    ]
  },
  "transport_socket": {
    "name": "envoy.transport_sockets.tls",
    "typed_config": {
      "common_tls_context": {
        "tls_certificate_sds_secret_configs": [
          {
            "name": "default",
            "sds_config": {
              "api_config_source": {
                "api_type": "GRPC",
                "grpc_services": [
                  {
                    "envoy_grpc": {
                      "cluster_name": "sds-grpc"
                    }
                  }
                ]
              }
            }
          }
        ]
      }
    }
  }
}

構成同期とデバッグ

proxy-statusで同期状態を確認

$ istioctl proxy-status
NAME                    CDS    LDS    EDS    RDS    ECDS   ISTIOD
frontend-v1-xxx.prod    SYNCED SYNCED SYNCED SYNCED        istiod-abc
reviews-v1-yyy.prod     SYNCED SYNCED SYNCED SYNCED        istiod-abc
ratings-v1-zzz.prod     STALE  SYNCED SYNCED SYNCED        istiod-abc

ステータスコード:

  • SYNCED:プロキシが最新の構成を受信済み
  • NOT SENT:istiodがまだ構成を送信していない
  • STALE:istiodが構成を送信したがACKを受信していない

構成差分の比較

# istiodが送信した構成とプロキシの現在の構成を比較
istioctl proxy-config all PODNAME -o json > proxy-config.json
istioctl proxy-status PODNAME --diff

パフォーマンスの考慮事項

コントロールプレーンのスケーリング

  • istiodは水平スケール可能(複数レプリカ)
  • 各Envoyは1つのistiodインスタンスに接続
  • istiod障害時、Envoyは最後に受信した構成で動作を継続

大規模メッシュでの最適化

  1. Sidecarリソースの使用:各ワークロードが知る必要のあるサービス範囲を制限
  2. exportToの設定:CRDの可視性範囲を制限
  3. イベントバッチ処理:istiodは短期間内の複数変更をまとめてプッシュ
  4. 増分xDS(Delta xDS):変更部分のみ送信
# SidecarリソースでEnvoyメモリを最適化
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
  name: default
  namespace: production
spec:
  egress:
    - hosts:
        - './*' # 同じネームスペースのサービス
        - 'istio-system/*' # Istioシステムサービス
        - 'monitoring/prometheus' # 特定の外部サービス

まとめ

Istioの内部アーキテクチャを理解すると、以下のメリットがあります:

  1. トラブルシューティング能力の向上:xDS同期問題、サイドカー注入失敗、証明書期限切れなどを迅速に診断
  2. パフォーマンス最適化:Sidecarリソース、接続プールチューニング、構成範囲制限などを適切に活用
  3. セキュリティ強化:mTLSの動作原理を理解し、正しいPeerAuthentication設定を行う

次の記事では、トラフィック管理エンジンの内部動作をさらに深く見ていきます。