Skip to content

필사 모드: サービスメッシュ(Service Mesh)実践ガイド: Istio·Envoy·Linkerd基盤mTLS·トラフィック管理·可観測性確保

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

はじめに

マイクロサービスアーキテクチャの普及に伴い、サービス間通信の複雑さが急激に増加している。認証、暗号化、トラフィック管理、可観測性、障害隔離などの横断的関心事(cross-cutting concerns)を各サービスに直接実装すると、コードの重複と運用負担が指数的に増大する。サービスメッシュ(Service Mesh)はこれらのネットワーキング関心事をインフラレイヤーに抽出し、アプリケーションコードの変更なしに一貫したセキュリティ、可観測性、トラフィック制御を提供する。

本記事では、サービスメッシュのコア概念であるデータプレーンとコントロールプレーンを説明し、Istio(Envoyサイドカー)とLinkerdを比較し、mTLS設定、トラフィック分割、サーキットブレーカー、可観測性ツール、そして最新のAmbient Meshまで実践例とともに解説する。本番環境で遭遇し得る代表的な障害シナリオと対応策も併せて整理する。

サービスメッシュコア概念

データプレーンとコントロールプレーン

サービスメッシュは大きく2つのレイヤーで構成される。

| レイヤー | 役割 | 実装 |

| -------------------- | -------------------------------------------------------------- | ------------------------------------------------ |

| データプレーン | サービス間の全ネットワークトラフィックをインターセプトして処理 | Envoy(Istio)、linkerd2-proxy(Linkerd) |

| コントロールプレーン | プロキシ設定配布、証明書管理、サービスディスカバリ | Istiod(Istio)、destination/identity(Linkerd) |

Istio vs Linkerd比較

| 項目 | Istio | Linkerd |

| -------------------------- | -------------------------------------------------- | ------------------------------------- |

| プロキシ | Envoy(C++) | linkerd2-proxy(Rust) |

| コントロールプレーン | Istiod(統合) | destination、identity、proxy-injector |

| プロキシメモリ | 約50MB+ / サイドカー | 約20-30MB / サイドカー |

| コントロールプレーンメモリ | 1-2GB(本番) | 200-300MB |

| L7機能 | 非常に豊富(ヘッダールーティング、ミラーリング等) | コア機能中心 |

| 学習曲線 | 急峻 | 緩やか |

| CRD数 | 50+ | 約10個 |

| Ambientモード | サポート(ztunnel + waypoint) | 未サポート |

| 適用環境 | 大規模、複雑なトラフィック管理 | 中小規模、迅速な導入 |

性能オーバーヘッド比較

ベンチマーク結果(2000 RPS基準)

P99レイテンシ追加量:

No mesh: 基準値

Linkerd: +2.0ms

Istio Sidecar: +5.8ms

Istio Ambient: +2.4ms

リソース使用量(サイドカー当たり):

Envoy: ~50MB RAM, ~0.5 vCPU

linkerd2-proxy: ~20MB RAM, ~0.2 vCPU

大規模環境(12800 RPS)ベンチマークにおいて

Istio Ambientが最低レイテンシを記録

Linkerd対比P99で約11msの差

Istioアーキテクチャと設定

Istioインストール

istioctl インストール

curl -L https://istio.io/downloadIstio | sh -

cd istio-1.24.0

export PATH=$PWD/bin:$PATH

本番プロファイルでインストール

istioctl install --set profile=default -y

ネームスペースにサイドカー自動インジェクション有効化

kubectl label namespace default istio-injection=enabled

インストール確認

istioctl verify-install

kubectl get pods -n istio-system

VirtualServiceとDestinationRule

VirtualService: トラフィックルーティングルール定義

apiVersion: networking.istio.io/v1

kind: VirtualService

metadata:

name: reviews-route

namespace: default

spec:

hosts:

- reviews

http:

- match:

- headers:

end-user:

exact: beta-tester

route:

- destination:

host: reviews

subset: v2

weight: 100

- route:

- destination:

host: reviews

subset: v1

weight: 90

- destination:

host: reviews

subset: v2

weight: 10

DestinationRule: サービスサブセットとポリシー定義

apiVersion: networking.istio.io/v1

kind: DestinationRule

metadata:

name: reviews-destination

namespace: default

spec:

host: reviews

trafficPolicy:

connectionPool:

tcp:

maxConnections: 100

http:

h2UpgradePolicy: DEFAULT

http1MaxPendingRequests: 100

http2MaxRequests: 1000

loadBalancer:

simple: ROUND_ROBIN

subsets:

- name: v1

labels:

version: v1

- name: v2

labels:

version: v2

trafficPolicy:

loadBalancer:

simple: LEAST_REQUEST

トラフィック分割(カナリアデプロイメント)

カナリアデプロイメント: v2へ段階的にトラフィック増加

apiVersion: networking.istio.io/v1

kind: VirtualService

metadata:

name: my-service-canary

spec:

hosts:

- my-service

http:

- route:

- destination:

host: my-service

subset: stable

weight: 95

- destination:

host: my-service

subset: canary

weight: 5

カナリアトラフィック比率段階的増加スクリプト

5% → 10% → 25% → 50% → 100%

for weight in 10 25 50 100; do

stable_weight=$((100 - weight))

kubectl patch virtualservice my-service-canary --type=json \

-p="[

{\"op\":\"replace\",\"path\":\"/spec/http/0/route/0/weight\",\"value\":${stable_weight}},

{\"op\":\"replace\",\"path\":\"/spec/http/0/route/1/weight\",\"value\":${weight}}

]"

echo "Canary weight: ${weight}%, Stable weight: ${stable_weight}%"

echo "Monitoring for 5 minutes..."

sleep 300

done

サーキットブレーカー設定

DestinationRuleを利用したサーキットブレーカー

apiVersion: networking.istio.io/v1

kind: DestinationRule

metadata:

name: payment-service-cb

spec:

host: payment-service

trafficPolicy:

connectionPool:

tcp:

maxConnections: 50

http:

http1MaxPendingRequests: 50

http2MaxRequests: 100

maxRequestsPerConnection: 10

maxRetries: 3

outlierDetection:

consecutive5xxErrors: 5

interval: 30s

baseEjectionTime: 30s

maxEjectionPercent: 50

minHealthPercent: 30

サーキットブレーカーステータス確認

istioctl proxy-config cluster <pod-name> --fqdn payment-service.default.svc.cluster.local -o json | grep -A 20 "outlierDetection"

Envoy統計でサーキットブレーカー動作確認

kubectl exec <pod-name> -c istio-proxy -- pilot-agent request GET stats | grep "circuit_breakers"

mTLS設定とセキュリティ

Strict mTLS適用

ネームスペース全体にStrict mTLS適用

apiVersion: security.istio.io/v1

kind: PeerAuthentication

metadata:

name: default

namespace: default

spec:

mtls:

mode: STRICT

メッシュ全体にStrict mTLS適用(istio-systemネームスペースに作成)

apiVersion: security.istio.io/v1

kind: PeerAuthentication

metadata:

name: default

namespace: istio-system

spec:

mtls:

mode: STRICT

特定ポート除外(レガシーサービス連携)

特定サービスで一部ポートのみPERMISSIVEモード

apiVersion: security.istio.io/v1

kind: PeerAuthentication

metadata:

name: legacy-integration

namespace: default

spec:

selector:

matchLabels:

app: legacy-adapter

mtls:

mode: STRICT

portLevelMtls:

8080:

mode: PERMISSIVE

証明書管理とSPIFFE

現在のmTLSステータス確認

istioctl authn tls-check <pod-name>

証明書情報確認

istioctl proxy-config secret <pod-name> -o json

SPIFFE ID形式: spiffe://cluster.local/ns/NAMESPACE/sa/SERVICE_ACCOUNT

IstioはKubernetesサービスアカウントに基づいてSPIFFE IDを自動割り当て

証明書有効期限確認(デフォルト24時間、自動更新)

kubectl exec <pod-name> -c istio-proxy -- \

openssl x509 -noout -dates -in /var/run/secrets/istio/tls/cert-chain.pem

証明書ローテーション強制実行(デバッグ用)

kubectl delete secret istio-ca-root-cert -n default

Istiodが自動的に新しい証明書を発行

Authorization Policy(アクセス制御)

特定サービスからのアクセスのみ許可

apiVersion: security.istio.io/v1

kind: AuthorizationPolicy

metadata:

name: payment-access

namespace: default

spec:

selector:

matchLabels:

app: payment-service

rules:

- from:

- source:

principals:

- cluster.local/ns/default/sa/order-service

- cluster.local/ns/default/sa/checkout-service

to:

- operation:

methods: ['POST', 'GET']

paths: ['/api/v1/payments/*']

全アクセス拒否(デフォルト拒否ポリシー)

apiVersion: security.istio.io/v1

kind: AuthorizationPolicy

metadata:

name: deny-all

namespace: default

spec: {}

Ambient Mesh(サイドカーレスモード)

Ambient Meshアーキテクチャ

Ambient Meshはサイドカーを排除し、2つのレイヤーでメッシュ機能を提供する。

| レイヤー | コンポーネント | 機能 |

| -------------------- | ------------------------------------ | -------------------------------------- |

| L4(Secure Overlay) | ztunnel(ノード毎DaemonSet) | mTLS、L4認可、L4テレメトリ |

| L7(Waypoint) | waypointプロキシ(ネームスペース毎) | HTTPルーティング、L7認可、L7テレメトリ |

AmbientモードでIstioインストール

istioctl install --set profile=ambient -y

ネームスペースをAmbientメッシュに追加

kubectl label namespace default istio.io/dataplane-mode=ambient

ztunnel DaemonSet確認

kubectl get pods -n istio-system -l app=ztunnel

L7機能が必要な場合Waypointプロキシをデプロイ

istioctl waypoint apply --namespace default --name default-waypoint

Waypointプロキシ確認

kubectl get pods -n default -l istio.io/gateway-name=default-waypoint

Ambient vs Sidecar比較

Sidecarモード:

長所: 完全なL7制御、成熟したエコシステム

短所: Pod毎のプロキシオーバーヘッド、再起動が必要

リソース: ~50MB RAM + ~0.5 vCPU / Pod

Ambientモード:

長所: Pod再起動不要、低リソースオーバーヘッド

短所: L7はwaypoint必要、比較的新しい技術

リソース: ztunnel ~30MB RAM / ノード + waypoint共有

選択基準:

既存ワークロード移行 → Ambientを優先検討

細かなL7制御が必要 → Sidecar維持

リソース節約優先 → Ambient

安定性優先 → Sidecar(より成熟)

可観測性(Observability)確保

Kiali ダッシュボード

Kialiインストール(Istioアドオン)

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/kiali.yaml

Kialiダッシュボードアクセス

istioctl dashboard kiali

Kialiが提供する情報:

- サービス間トラフィックフローグラフ

- リクエスト成功率 / エラー率

- P50/P90/P99レイテンシ

- mTLSステータス(ロックアイコン)

- Istio設定検証(エラーハイライト)

分散トレーシング(Jaeger/Zipkin)

Jaegerインストール

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/jaeger.yaml

Jaegerダッシュボードアクセス

istioctl dashboard jaeger

アプリケーションでトレースヘッダーの伝播が必須

以下のヘッダーをupstreamに転送する必要がある:

x-request-id

x-b3-traceid

x-b3-spanid

x-b3-parentspanid

x-b3-sampled

x-b3-flags

traceparent

tracestate

Python Flaskでのトレースヘッダー伝播例

from flask import Flask, request

app = Flask(__name__)

TRACE_HEADERS = [

'x-request-id',

'x-b3-traceid',

'x-b3-spanid',

'x-b3-parentspanid',

'x-b3-sampled',

'x-b3-flags',

'traceparent',

'tracestate',

]

def propagate_headers():

headers = {}

for header in TRACE_HEADERS:

value = request.headers.get(header)

if value:

headers[header] = value

return headers

@app.route('/api/orders')

def get_orders():

ダウンストリームサービス呼び出し時にトレースヘッダーを伝播

headers = propagate_headers()

response = requests.get(

'http://payment-service:8080/api/payments',

headers=headers

)

return response.json()

Prometheus + Grafanaメトリクス

PrometheusとGrafanaインストール

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/prometheus.yaml

kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/addons/grafana.yaml

Grafanaダッシュボードアクセス

istioctl dashboard grafana

Istioが自動収集する主要メトリクス:

istio_requests_total - 総リクエスト数

istio_request_duration_milliseconds - リクエストレイテンシ

istio_request_bytes - リクエストサイズ

istio_response_bytes - レスポンスサイズ

istio_tcp_connections_opened_total - TCP接続数

Prometheusでの主要クエリ例

サービス別エラー率(5xx)

rate(istio_requests_total{response_code=~"5.."}[5m])

/

rate(istio_requests_total[5m])

P99レイテンシ

histogram_quantile(0.99,

sum(rate(istio_request_duration_milliseconds_bucket[5m]))

by (le, destination_service_name))

障害シナリオと対応

シナリオ1: サイドカーインジェクション失敗

症状: PodはRunningだがサイドカー(istio-proxy)がない

1. ネームスペースラベル確認

kubectl get namespace default --show-labels

istio-injection=enabledラベルがあるか確認

2. Podのコンテナリスト確認

kubectl get pod <pod-name> -o jsonpath='{.spec.containers[*].name}'

istio-proxyがリストにない場合インジェクション失敗

3. 原因診断

a. ネームスペースラベル欠如

kubectl label namespace default istio-injection=enabled

b. Podにインジェクション無効化アノテーションがある場合

kubectl get pod <pod-name> -o jsonpath='{.metadata.annotations.sidecar\.istio\.io/inject}'

"false"の場合インジェクションが無効化された状態

c. Webhook設定確認

kubectl get mutatingwebhookconfiguration istio-sidecar-injector -o yaml

4. 手動インジェクション(緊急時)

istioctl kube-inject -f deployment.yaml | kubectl apply -f -

5. Pod再起動(インジェクション適用のため)

kubectl rollout restart deployment <deployment-name>

シナリオ2: 証明書ローテーション失敗

症状: サービス間通信失敗、TLSハンドシェイクエラー

1. 証明書ステータス確認

istioctl proxy-config secret <pod-name>

VALIDステータスと有効期限確認

2. Istiodログで証明書関連エラー確認

kubectl logs -n istio-system deployment/istiod | grep -i "certificate\|cert\|error"

3. CA証明書確認

kubectl get secret istio-ca-secret -n istio-system -o jsonpath='{.data.ca-cert\.pem}' | base64 -d | openssl x509 -noout -dates

4. 証明書強制更新

Podのistio-proxyを再起動

kubectl delete pod <pod-name>

5. Istiod再起動(CA問題の場合)

kubectl rollout restart deployment istiod -n istio-system

6. Root CAローテーション(計画された作業)

新しいRoot CA作成後、中間CAを通じた段階的切替

公式ドキュメントのCA rotation guideを参照

シナリオ3: 過剰メモリ使用(Envoy OOM)

症状: istio-proxyコンテナがOOMKilledで再起動

1. 現在のリソース使用量確認

kubectl top pod <pod-name> --containers

2. Envoy統計確認

kubectl exec <pod-name> -c istio-proxy -- pilot-agent request GET stats/memory

3. リソース制限調整

kubectl patch deployment <deployment-name> --type=json \

-p='[{"op":"replace","path":"/spec/template/metadata/annotations/sidecar.istio.io~1proxyMemoryLimit","value":"512Mi"}]'

4. グローバルプロキシリソース設定(IstioOperator)

istio-operator.yamlで以下のように設定

spec:

meshConfig:

defaultConfig:

proxyMetadata: {}

values:

global:

proxy:

resources:

requests:

cpu: 100m

memory: 128Mi

limits:

cpu: 500m

memory: 512Mi

運用時の注意事項

1. **段階的導入**: サービスメッシュを一度にクラスター全体に適用せず、非クリティカルなワークロードから段階的に拡張する。PERMISSIVE mTLSモードから始めてSTRICTに移行する。

2. **リソース予算確保**: Envoyサイドカー基準でPod毎に約50MB RAM + 0.5 vCPUを追加確保する。大規模クラスターではこのオーバーヘッドが相当な量になる可能性がある。

3. **トレースヘッダー伝播**: 分散トレーシングが正しく機能するには、アプリケーションでトレースヘッダー(x-b3-traceidなど)を必ず伝播する必要がある。サービスメッシュが自動的に行わない部分である。

4. **CRD管理**: Istioは50以上のCRDを使用する。アップグレード時にCRDの互換性を必ず確認し、カナリアアップグレードを推奨する。

5. **Ambient Meshの検討**: 新規導入であればAmbient Meshを積極的に検討する。サイドカーオーバーヘッドなしにL4セキュリティを即座に確保でき、L7機能は必要なサービスにのみwaypointをデプロイすればよい。

6. **Istiod高可用性**: 本番環境ではIstiodを最低2つ以上のレプリカで運用し、Pod Disruption Budgetを設定する。

Istiodレプリカ拡張

kubectl scale deployment istiod -n istio-system --replicas=3

PDB設定

kubectl apply -f - <<ENDF

apiVersion: policy/v1

kind: PodDisruptionBudget

metadata:

name: istiod-pdb

namespace: istio-system

spec:

minAvailable: 1

selector:

matchLabels:

app: istiod

ENDF

まとめ

サービスメッシュは、マイクロサービス環境においてセキュリティ、可観測性、トラフィック管理という3つのコア課題をインフラレベルで解決する。Istioは豊富な機能と細かな制御を、Linkerdは軽量化と迅速な導入を強みとしている。最新のAmbient Meshはサイドカーオーバーヘッドを排除しつつコアセキュリティ機能を提供することで、サービスメッシュ導入の障壁を大幅に下げている。

本番環境で最も重要なのは段階的導入である。PERMISSIVE mTLSから始めて可観測性を確保し、安定性を確認した後STRICTモードに移行する段階的アプローチが成功の鍵である。サービスメッシュが提供する一貫した可観測性とセキュリティは、マイクロサービス運用の複雑さを大幅に軽減してくれるだろう。

参考資料

- [Istio Architecture - Official Documentation](https://istio.io/latest/docs/ops/deployment/architecture/)

- [Istio Ambient Mesh Overview](https://istio.io/latest/docs/ambient/overview/)

- [Istio Performance and Scalability](https://istio.io/latest/docs/ops/deployment/performance-and-scalability/)

- [Linkerd vs Istio - Buoyant](https://www.buoyant.io/linkerd-vs-istio)

- [Mutual TLS: Securing Microservices in Service Mesh - The New Stack](https://thenewstack.io/mutual-tls-microservices-encryption-for-service-mesh/)

- [Service Mesh Architecture: Istio and Envoy in Production - Java Code Geeks](https://www.javacodegeeks.com/2025/11/service-mesh-architecture-istio-and-envoy-in-production.html)

- [Performance Comparison of Service Mesh Frameworks - arXiv](https://arxiv.org/html/2411.02267v1)

현재 단락 (1/278)

マイクロサービスアーキテクチャの普及に伴い、サービス間通信の複雑さが急激に増加している。認証、暗号化、トラフィック管理、可観測性、障害隔離などの横断的関心事(cross-cutting concern...

작성 글자: 0원문 글자: 12,314작성 단락: 0/278