Istio によるサービス間通信の制御・mTLS・トラフィック管理・Kiali 可視化を EKS で体験する
Service Mesh はマイクロサービス間の通信を管理するインフラレイヤーです。各サービスのサイドカーとして Envoy プロキシを自動注入し、アプリコードを変更せずにトラフィック制御・相互 TLS・可観測性を実現します。
このハンズオンでは CNCF Graduated プロジェクトの Istio を EKS 上にインストールし、Bookinfo サンプルアプリを通じてサービスメッシュの主要機能を体験します。
Linkerd は軽量で EKS への導入が容易ですが、このハンズオンでは以下の理由から Istio を採用しています。
シンプルな mTLS と基本的なトラフィック管理が目的であれば Linkerd も優れた選択肢です。
| 項目 | 内容 |
|---|---|
| 対象ツール | Amazon EKS、Istio 1.24+、Envoy、Kiali、Jaeger(Istio アドオン) |
| 主な学習内容 | サイドカー注入・mTLS 確認・トラフィック分割・Fault Injection・Kiali 可視化 |
| 所要時間 | 120〜150 分 |
| 難易度 | ★★★★☆(上級者向け) |
| 前提知識 | Kubernetes の基本操作・YAML の読み書き・TLS の基本概念 |
| 費用目安 | 約 4〜8 USD(EKS クラスター + t3.large × 3 ノード) |
| サービス | 役割 | バージョン |
|---|---|---|
| productpage | フロントエンド(Python) | v1 |
| details | 書籍詳細 API(Ruby) | v1 |
| reviews | レビュー API(Java) | v1(星なし)/ v2(黒星)/ v3(赤星) |
| ratings | 評価スコア API(Node.js) | v1 |
reviews サービスが 3 バージョン存在し、トラフィック分割の体験に使います。
kubectl・AWS CLI がインストール済みであることIstio の Control Plane(istiod)と Ingress/Egress Gateway が起動します。最小 t3.medium × 3 台、推奨 t3.large × 3 台です。
t3.large × 3 ノードの EKS クラスターは 1 時間あたり約 $0.50 かかります。ハンズオン終了後は必ずクリーンアップしてください。
eksctl create cluster \ --name mesh-handson \ --version 1.33 \ --region ap-northeast-1 \ --nodegroup-name workers \ --node-type t3.large \ --nodes 3 \ --managed
kubectl get nodes # 3 ノードが Ready であることを確認
3 つのノードがすべて Ready 状態で表示されれば次のステップに進めます。
istioctl を使って Istio をインストールします。
# 最新の安定版をダウンロード curl -L https://istio.io/downloadIstio | sh - # ダウンロードされたディレクトリに移動(バージョン番号は実際のものに合わせる) cd istio-1.24.*/ export PATH=$PWD/bin:$PATH # バージョン確認 istioctl version --remote=false
# PowerShell $ISTIO_VERSION = "1.24.3" Invoke-WebRequest -Uri "https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istioctl-$ISTIO_VERSION-win-amd64.zip" -OutFile "istioctl.zip" Expand-Archive -Path "istioctl.zip" -DestinationPath "." $env:PATH = "$PWD;" + $env:PATH
demo プロファイルはすべての機能(Ingress/Egress Gateway 含む)を含み、学習目的に最適です。
istioctl install --set profile=demo -y
インストールに 3〜5 分かかります。
kubectl get pods -n istio-system
以下の Pod が Running になるのを確認します。
istiod-xxx(Control Plane)istio-ingressgateway-xxx(Ingress Gateway)istio-egressgateway-xxx(Egress Gateway)kubectl apply -f samples/addons/kiali.yaml kubectl apply -f samples/addons/prometheus.yaml kubectl apply -f samples/addons/grafana.yaml kubectl apply -f samples/addons/jaeger.yaml # 起動待ち kubectl rollout status deployment/kiali -n istio-system --timeout=120s
kubectl get pods -n istio-system ですべての Pod が Running になれば成功です。
kubectl label namespace default istio-injection=enabled kubectl get namespace default --show-labels
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml
kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
kubectl apply -f samples/bookinfo/networking/destination-rule-all.yaml
kubectl get svc istio-ingressgateway -n istio-system
EXTERNAL-IP の値が払い出されるまで 1〜2 分待ちます(EKS が NLB/ELB を作成します)。
# EXTERNAL-IP を変数に保存
export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "http://$INGRESS_HOST/productpage"
ブラウザで http://<EXTERNAL-IP>/productpage を開きます。Bookinfo の商品詳細ページが表示されます。
何度かリロードすると reviews セクションの星の表示が変わります(v1: 星なし / v2: 黒星 / v3: 赤星)。
Bookinfo の productpage が表示され、リロードのたびに reviews のバージョンが変わることを確認できれば成功です。
kubectl get pods
各 Pod が 2/2(アプリコンテナ + Envoy サイドカー)になっていることを確認します。
NAME READY STATUS RESTARTS AGE details-v1-xxx 2/2 Running 0 3m productpage-v1-xxx 2/2 Running 0 3m ratings-v1-xxx 2/2 Running 0 3m reviews-v1-xxx 2/2 Running 0 3m reviews-v2-xxx 2/2 Running 0 3m reviews-v3-xxx 2/2 Running 0 3m
kubectl describe pod -l app=productpage | grep -A5 "Containers:"
istio-proxy(Envoy)コンテナが含まれていることを確認します。
# istioctl でポッドのプロキシ設定を確認
istioctl proxy-config cluster \
$(kubectl get pod -l app=productpage -o jsonpath='{.items[0].metadata.name}') | head -20
すべての Bookinfo Pod が 2/2 で起動し、istio-proxy コンテナが含まれていれば Envoy サイドカーが正常に注入されています。
for i in $(seq 1 30); do
curl -s "http://$INGRESS_HOST/productpage" -o /dev/null -w "%{http_code}\n"
sleep 1
done
istioctl proxy-status
すべての Pod の CDS・LDS・RDS・EDS が SYNCED であることを確認します。これは Istio Control Plane から Envoy への設定配布が完了していることを意味します。
すべての Pod が SYNCED 状態で表示されれば、Istio がサービス間通信を管理できています。
Istio はデフォルトで PERMISSIVE モード(mTLS と平文の両方を受け入れ)で動作します。STRICT モードに変更してサービス間通信をすべて暗号化します。
istioctl authn tls-check \
$(kubectl get pod -l app=productpage -o jsonpath='{.items[0].metadata.name}')
現在は PERMISSIVE または AUTO モードのため、mTLS と平文の両方が通過します。
kubectl apply -f - <<'EOF'
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: default
namespace: default
spec:
mtls:
mode: STRICT
EOF
istioctl authn tls-check \
$(kubectl get pod -l app=productpage -o jsonpath='{.items[0].metadata.name}')
モードが STRICT に変わり、すべての通信が mTLS で暗号化されていることを確認します。
# サイドカーなしの Pod から平文で通信を試みる kubectl run test-curl --image=curlimages/curl --restart=Never -- \ curl -s http://productpage:9080/productpage kubectl logs test-curl # mTLS STRICT モードでは接続が拒否される
istioctl authn tls-check でモードが STRICT になり、サイドカーなし Pod からの平文通信が拒否されれば mTLS が正常に機能しています。
reviews サービスへのトラフィックをバージョン別に重み付けして振り分けます。
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 100
EOF
ブラウザで productpage を何度リロードしても、reviews が常に v1(星なし)になります。
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 80
- destination:
host: reviews
subset: v3
weight: 20
EOF
productpage を 10 回リロードすると、約 2 回(20%)が v3(赤星)になります。
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v3
weight: 100
EOF
重み付けを変えることで、productpage のリロード結果が期待通りの割合で v1/v3 に分散されれば成功です。アプリコードは一切変更せずにトラフィック制御ができています。
Istio の Fault Injection を使って、意図的に遅延やエラーを発生させ、アプリの耐障害性を確認します。
ratings サービスへのリクエストの 50% に 7 秒の遅延を注入します。
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
delay:
percentage:
value: 50
fixedDelay: 7s
route:
- destination:
host: ratings
subset: v1
EOF
productpage を開くと、約 50% の確率で 7 秒後に ratings が「Ratings service is currently unavailable」と表示されます。
reviews が ratings を呼び出す際のタイムアウトを 0.5 秒に設定します(遅延 7 秒 > タイムアウト 0.5 秒なので必ずタイムアウトする)。
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v2
timeout: 0.5s
EOF
遅延を削除し、代わりにエラーレスポンスへのリトライを設定します。
# まず遅延と timeout を削除
kubectl delete virtualservice ratings
kubectl delete virtualservice reviews
# エラー注入(HTTP 500)を 100% で設定し、3 回リトライする
kubectl apply -f - <<'EOF'
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: ratings
spec:
hosts:
- ratings
http:
- fault:
abort:
percentage:
value: 100
httpStatus: 500
retries:
attempts: 3
perTryTimeout: 2s
route:
- destination:
host: ratings
subset: v1
EOF
kubectl delete virtualservice ratings kubectl delete virtualservice reviews
遅延注入でページの応答が遅くなり、タイムアウト設定でエラーメッセージが表示されることを確認できれば、Fault Injection の動作を理解できています。
Kiali は Istio 専用のオブザーバビリティダッシュボードです。サービス間の通信グラフ・メトリクス・設定状態を一画面で確認できます。
istioctl dashboard kiali
ブラウザが自動で開きます(http://localhost:20001)。または別ターミナルで以下を実行します。
kubectl port-forward -n istio-system svc/kiali 20001:20001
左メニューの 「Graph」 をクリックします。
default を選択グラフのノード(サービス)をクリックすると、右パネルにそのサービスの詳細メトリクス(RPS・レイテンシ・エラー率)が表示されます。
左メニューの 「Istio Config」 から VirtualService・DestinationRule などの設定の整合性(Validation)を確認できます。設定ミスがあれば赤いアイコンで警告されます。
# Grafana(Istio アドオン) istioctl dashboard grafana # Jaeger(Istio アドオン) istioctl dashboard jaeger
Grafana では Istio Service Dashboard・Istio Workload Dashboard でサービスレベルのメトリクスが確認できます。
Kiali のグラフで Bookinfo サービス間の通信が矢印で表示され、各サービスの RPS・エラー率・レイテンシが確認できれば成功です。
| 課題 | Istio による解決 |
|---|---|
| サービス間の平文通信(盗聴リスク) | PeerAuthentication + mTLS STRICT で自動暗号化 |
| 特定バージョンのカナリアリリース | VirtualService + weight でコードなしにトラフィック分割 |
| ダウンストリームの障害による連鎖障害 | タイムアウト・リトライ・Circuit Breaker で保護 |
| サービス間通信の可視化困難 | Kiali で通信グラフをリアルタイム表示 |
| CRD | 役割 | 例 |
|---|---|---|
| VirtualService | トラフィックルーティング・Fault Injection | 重み付きルーティング・タイムアウト |
| DestinationRule | サービスのサブセット定義・接続プール設定 | v1/v2/v3 のサブセット定義 |
| PeerAuthentication | mTLS ポリシー設定 | STRICT / PERMISSIVE |
| AuthorizationPolicy | L4/L7 のアクセス制御 | 特定 SA からのみ許可 |
| Gateway | 外部トラフィックのエントリポイント設定 | Ingress Gateway のホスト・ポート設定 |
ハンズオン完了後は以下の順序でリソースを削除してください。
Istio Ingress Gateway に作成された ELB(ロードバランサー)も課金対象です。必ずクリーンアップを実施してください。
kubectl delete -f samples/bookinfo/platform/kube/bookinfo.yaml kubectl delete -f samples/bookinfo/networking/bookinfo-gateway.yaml kubectl delete -f samples/bookinfo/networking/destination-rule-all.yaml
kubectl delete peerauthentication default kubectl delete virtualservice reviews ratings 2>/dev/null; true
kubectl delete -f samples/addons/kiali.yaml kubectl delete -f samples/addons/prometheus.yaml kubectl delete -f samples/addons/grafana.yaml kubectl delete -f samples/addons/jaeger.yaml
istioctl uninstall --purge -y kubectl delete namespace istio-system
kubectl label namespace default istio-injection-
kubectl delete pod test-curl --ignore-not-found
eksctl delete cluster --name mesh-handson --region ap-northeast-1
ELB の削除を含めて 10〜15 分かかります。CloudFormation コンソールでスタックが消えたことを確認してください。