Skip to content
Published on

Istioオブザーバビリティ内部実装:メトリクス、トレーシング、ロギング

Authors

はじめに

オブザーバビリティ(Observability)はサービスメッシュの核心的価値の一つです。Istioはアプリケーションコードの修正なしにメトリクス、分散トレーシング、アクセスロギングを自動的に生成します。

この記事ではIstioがどのようにこれらのテレメトリデータを生成し、Envoyフィルターチェーンでどのような処理が行われ、外部システムとどのように統合されるかの内部実装を分析します。

Envoy統計システム

統計タイプ

Envoyは3種類の統計を生成します:

タイプ説明
Counter単調増加する値総リクエスト数、総エラー数
Gauge増加/減少可能な現在値アクティブ接続数、待機中リクエスト数
Histogram値の分布リクエストレイテンシ、レスポンスサイズ

フィルターチェーンでの統計生成

リクエストフローと統計生成位置:

Listener (connection stats)
    |
    v
HTTP Connection Manager (request stats)
    |
    +-- JWT Authn Filter -> 認証成功/失敗カウンター
    +-- RBAC Filter -> 認可許可/拒否カウンター
    +-- Fault Filter -> 注入された遅延/中断カウンター
    +-- Stats Filter (istio.stats) -> Istio標準メトリクス生成
    +-- Router Filter -> アップストリームリクエスト統計
    |
    v
Cluster (upstream stats)
    |
    v
Endpoint (connection/request stats)

Istio標準メトリクス

核心HTTPメトリクス

istio_requests_total (Counter)

リクエスト数を追跡する核心メトリクス:

istio_requests_total{
  reporter="source",                    # または"destination"
  source_workload="frontend",
  source_workload_namespace="prod",
  source_principal="spiffe://cluster.local/ns/prod/sa/frontend",
  destination_workload="reviews",
  destination_workload_namespace="prod",
  destination_principal="spiffe://cluster.local/ns/prod/sa/reviews",
  destination_service="reviews.prod.svc.cluster.local",
  destination_service_name="reviews",
  destination_service_namespace="prod",
  request_protocol="http",
  response_code="200",
  response_flags="-",
  connection_security_policy="mutual_tls"
}

istio_request_duration_milliseconds (Histogram)

リクエスト処理時間分布:

istio_request_duration_milliseconds_bucket{
  ...,  # 上記と同一のラベル
  le="1"
} 100
istio_request_duration_milliseconds_bucket{le="5"} 250
istio_request_duration_milliseconds_bucket{le="10"} 380
istio_request_duration_milliseconds_bucket{le="25"} 450
istio_request_duration_milliseconds_bucket{le="50"} 490
istio_request_duration_milliseconds_bucket{le="100"} 498
istio_request_duration_milliseconds_bucket{le="+Inf"} 500

istio_request_bytes / istio_response_bytes (Histogram)

リクエスト/レスポンスサイズ分布を追跡します。

TCPメトリクス

istio_tcp_sent_bytes_total         # 送信バイト総量
istio_tcp_received_bytes_total     # 受信バイト総量
istio_tcp_connections_opened_total # 開かれた接続数
istio_tcp_connections_closed_total # 閉じられた接続数

メトリクス生成位置:Source vs Destination

Frontend Pod                    Reviews Pod
[App] -> [Envoy]  -------->  [Envoy] -> [App]
          |                    |
     reporter="source"    reporter="destination"
     (アウトバウンド側記録)(インバウンド側記録)

両側のEnvoyがメトリクスを生成しますが、reporterラベルで区別されます。一般的に"source"リポーターはクライアント視点、"destination"はサーバー視点のメトリクスを提供します。

Telemetry API v2

アーキテクチャの進化

Istio 1.x(Mixerベース):
App -> Envoy -> Mixer -> Prometheus/Zipkin
               (別サービス、高レイテンシ)

Istio 1.12+(Telemetry API v2):
App -> Envoy(内蔵Stats/Traceフィルター) -> Prometheus/Zipkin
       (プロキシ内部処理、低レイテンシ)

Mixerが削除された後、メトリクス生成はEnvoyプロキシ内部で直接実行されます。

Telemetryリソース

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: mesh-default
  namespace: istio-system # メッシュ全体に適用
spec:
  # メトリクス設定
  metrics:
    - providers:
        - name: prometheus
      overrides:
        - match:
            metric: REQUEST_COUNT
            mode: CLIENT_AND_SERVER
          tagOverrides:
            request_host:
              operation: UPSERT
              value: 'request.host'

  # トレーシング設定
  tracing:
    - providers:
        - name: zipkin
      randomSamplingPercentage: 1.0
      customTags:
        environment:
          literal:
            value: 'production'

  # アクセスロギング設定
  accessLogging:
    - providers:
        - name: envoy
      filter:
        expression: 'response.code >= 400'

メトリクスカスタマイズ

# 特定メトリクスの無効化
spec:
  metrics:
  - providers:
    - name: prometheus
    overrides:
    - match:
        metric: REQUEST_BYTES
      disabled: true

# カスタムタグの追加
    overrides:
    - match:
        metric: REQUEST_COUNT
      tagOverrides:
        custom_tag:
          operation: UPSERT
          value: "request.headers['x-custom-tag']"

分散トレーシング

トレース伝播メカニズム

Envoyが自動的に行うこと:
+-- インバウンドリクエストからトレースヘッダーを抽出
+-- スパン(span)生成とタイミング記録
+-- スパンをトレースコレクターに送信
+-- アウトバウンドリクエストにトレースヘッダーを追加

アプリケーションが行うべきこと:
+-- インバウンドリクエストのトレースヘッダーをアウトバウンドリクエストにコピー
    (これをしないとトレースが途切れる)

サポートするトレースヘッダー

B3ヘッダー(Zipkin):

x-b3-traceid:      128ビットトレースID
x-b3-spanid:       64ビットスパンID
x-b3-parentspanid: 64ビット親スパンID
x-b3-sampled:      サンプリング可否(0または1x-b3-flags:        デバッグフラグ

W3C TraceContext:

traceparent: 00-TRACE_ID-SPAN_ID-FLAGS
tracestate:  ベンダー固有のkey=valueペア

Envoy内部ヘッダー:

x-request-id: Envoyが生成するUUID(トレースと連携)

スパン生成詳細

Frontend -> Reviews -> Ratings呼び出し時:

Frontend Envoy(アウトバウンド):
  Span: "reviews.prod.svc.cluster.local:9080/*"
  +-- Start: リクエスト送信開始
  +-- End: レスポンス受信完了
  +-- Tags: upstream_cluster, http.method, http.status_code
  +-- Parent: インバウンドスパン

Reviews Envoy(インバウンド):
  Span: "reviews.prod.svc.cluster.local:9080/*"
  +-- Start: リクエスト受信
  +-- End: レスポンス送信
  +-- Tags: downstream_cluster, peer.address

Reviews Envoy(アウトバウンド):
  Span: "ratings.prod.svc.cluster.local:9080/*"
  +-- Start: リクエスト送信開始
  +-- End: レスポンス受信完了
  +-- Parent: インバウンドスパン

トレースサンプリング

# MeshConfigで設定
meshConfig:
  defaultConfig:
    tracing:
      sampling: 1.0 # 1%(デフォルト値)
      # sampling: 100.0  # 100%(デバッグ用)

# またはTelemetry APIで設定
apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: tracing
spec:
  tracing:
    - randomSamplingPercentage: 1.0

サンプリング決定は最初のEnvoyで行われ、x-b3-sampledヘッダーを通じて伝播されます。以降のEnvoyはこの決定に従います。

トレースコレクター統合

# Zipkin統合
meshConfig:
  defaultConfig:
    tracing:
      zipkin:
        address: zipkin.istio-system:9411

# Jaeger統合(Zipkin互換エンドポイント使用)
meshConfig:
  defaultConfig:
    tracing:
      zipkin:
        address: jaeger-collector.observability:9411

# OpenTelemetry Collector統合
meshConfig:
  extensionProviders:
  - name: otel
    opentelemetry:
      service: otel-collector.observability.svc.cluster.local
      port: 4317

アクセスロギング

Envoyアクセスログ形式

デフォルトログ形式:

[2026-03-20T10:30:00.000Z] "GET /api/reviews HTTP/1.1" 200 - via_upstream
  - "-" 0 1234 5 3
  "-" "curl/7.68.0" "abc-123-def"
  "reviews.prod.svc.cluster.local:9080"
  inbound|9080||reviews.prod.svc.cluster.local
  10.244.1.5:9080 10.244.0.3:48292
  outbound_.9080_.v1_.reviews.prod.svc.cluster.local default

ログフィールド説明

[タイムスタンプ] "メソッド パス プロトコル" ステータスコード レスポンスフラグ
  - "-" リクエストバイト レスポンスバイト 処理時間(ms) アップストリーム時間(ms)
  "-" "User-Agent" "Request-ID"
  "アップストリームホスト"
  ルート名
  ダウンストリームアドレス アップストリームアドレス
  クラスタ名 ネームスペース

レスポンスフラグ(Response Flags)

フラグ意味
-正常レスポンス
UHアップストリーム不健全(全てejected)
UFアップストリーム接続失敗
UOアップストリームオーバーフロー(サーキットブレーカー)
NRルートなし
URXリトライ上限超過
DCダウンストリーム接続終了
LHローカルヘルスチェック失敗
UTアップストリームタイムアウト
RLレートリミット
UAEX外部認可拒否
RLSEレートリミットサービスエラー

条件付きロギング

Telemetry APIを使用した条件付きアクセスロギング:

apiVersion: telemetry.istio.io/v1alpha1
kind: Telemetry
metadata:
  name: access-log-errors
  namespace: production
spec:
  accessLogging:
    - providers:
        - name: envoy
      filter:
        expression: 'response.code >= 400 || connection.mtls == false'

CEL(Common Expression Language)式を使用してロギング条件を細かく制御できます。

Kiali:サービスメッシュ可視化

Kialiアーキテクチャ

Kialiデータソース:
+-- Prometheus -> メトリクスベースのサービスグラフ
+-- Kubernetes API -> ワークロード、サービス情報
+-- Istio Config API -> VirtualService、DestinationRuleなど
+-- Jaeger/Tempo -> 分散トレース(オプション)

Kialiが提供する情報

1. サービスグラフ(Topology)
   +-- サービス間トラフィックフロー
   +-- リクエスト成功/失敗率
   +-- 秒間リクエスト数
   +-- レスポンス時間

2. ワークロード健全性
   +-- エラー率ベースの健全性スコア
   +-- インバウンド/アウトバウンドメトリクス
   +-- Pod状態

3. Istio構成検証
   +-- VirtualService有効性
   +-- DestinationRule競合検出
   +-- 参照整合性(存在しないhostなど)
   +-- ベストプラクティス違反

4. トラフィック分析
   +-- 時間別トラフィック推移
   +-- エラーパターン識別
   +-- レイテンシ分布

Prometheus統合

メトリクス収集構成

IstioはPrometheusのサービスディスカバリを活用します:

# Prometheus scrape構成
scrape_configs:
  - job_name: 'envoy-stats'
    metrics_path: /stats/prometheus
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_container_name]
        action: keep
        regex: istio-proxy
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        target_label: __address__
        regex: (.+)
        replacement: 'target:15090'

各Envoyプロキシはポート15090でPrometheusメトリクスを公開します。

有用なPromQLクエリ

# サービス別リクエスト成功率(直近5分)
sum(rate(istio_requests_total{
  response_code!~"5.*",
  reporter="destination"
}[5m])) by (destination_service_name)
/
sum(rate(istio_requests_total{
  reporter="destination"
}[5m])) by (destination_service_name)

# P99レイテンシ
histogram_quantile(0.99,
  sum(rate(istio_request_duration_milliseconds_bucket{
    reporter="source"
  }[5m])) by (le, destination_service_name)
)

# サービス別秒間リクエスト数
sum(rate(istio_requests_total{
  reporter="destination"
}[5m])) by (destination_service_name)

Grafanaダッシュボード

Istio標準ダッシュボード

Istioは以下のGrafanaダッシュボードを提供します:

1. Mesh Dashboard
   +-- メッシュ全体サマリー(サービス数、エラー率、トラフィック)

2. Service Dashboard
   +-- サービス別詳細(インバウンド/アウトバウンド、エラー率、レイテンシ)

3. Workload Dashboard
   +-- ワークロード別詳細(Pod単位メトリクス)

4. Control Plane Dashboard
   +-- istiodパフォーマンス(xDSプッシュ数、レスポンス時間、エラー)

5. Performance Dashboard
   +-- Envoyリソース使用量(メモリ、CPU、接続数)

Jaeger/Zipkin/Tempo統合

分散トレーシングバックエンド

サポートするトレーシングバックエンド:

Zipkin
+-- 軽量、シンプルなインストール
+-- インメモリまたはCassandra/Elasticsearch保存
+-- Istioデフォルトサポート

Jaeger
+-- Zipkin互換API
+-- 多様なストレージバックエンドサポート
+-- Sparkベース分析
+-- プロダクション推奨

Tempo(Grafana)
+-- オブジェクトストレージベース(S3GCS+-- 高いスケーラビリティ
+-- Grafanaとネイティブ統合
+-- コスト効率的

トレースデータフロー

[1] リクエストがメッシュに進入
        |
[2] 最初のEnvoyがトレースID生成
    (既存ヘッダーがない場合)
        |
[3] 各Envoyがスパン生成しコレクターに送信
    +-- Zipkin: HTTP POST /api/v2/spans
    +-- Jaeger: UDP/gRPC
    +-- OTLP: gRPC (OpenTelemetry)
        |
[4] コレクターがスパンをトレースに組み立て
        |
[5] UIでトレース照会

デバッグのヒント

メトリクス確認

# 特定PodのEnvoyメトリクス直接確認
kubectl exec PODNAME -c istio-proxy -- \
  curl -s localhost:15090/stats/prometheus | grep istio_requests

# Envoy管理APIで統計確認
kubectl exec PODNAME -c istio-proxy -- \
  curl -s localhost:15000/stats | grep -E "^cluster\."

# Envoyサーバー情報
kubectl exec PODNAME -c istio-proxy -- \
  curl -s localhost:15000/server_info

トレーシング確認

# トレースヘッダー伝播確認
kubectl exec PODNAME -c istio-proxy -- \
  curl -s localhost:15000/config_dump | python3 -c "
import json, sys
config = json.load(sys.stdin)
for c in config.get('configs', []):
    if 'tracing' in str(c):
        print(json.dumps(c, indent=2))
"

アクセスログ確認

# リアルタイムアクセスログ確認
kubectl logs PODNAME -c istio-proxy -f | grep -v healthz

# エラーレスポンスのみフィルタリング
kubectl logs PODNAME -c istio-proxy | grep -E '"[45][0-9]{2}"'

まとめ

Istioのオブザーバビリティは、Envoyプロキシの豊富なテレメトリ機能の上に構築されています。核心ポイントをまとめると:

  1. メトリクス:EnvoyのStatsフィルターがistio_requests_total等の標準メトリクスを生成し、Prometheusが収集
  2. トレーシング:Envoyが自動的にスパンを生成するが、アプリケーションがトレースヘッダーを伝播してこそend-to-endトレーシングが可能
  3. ロギング:Envoyアクセスログがすべてのリクエスト/レスポンスを記録し、Telemetry APIで条件付きロギングが可能
  4. 可視化:KialiがPrometheusメトリクスを基にサービスグラフを生成

Istio Internalsシリーズを通じて、コントロールプレーン、トラフィック管理、セキュリティ、Ambient Mesh、オブザーバビリティの内部動作を見てきました。これらの内部理解が実務でサービスメッシュを効果的に運用する際の助けになることを願っています。