Cloud Service Mesh 入門編-Google のマネージドサービスメッシュを理解する

Sreake事業部

2025.9.25

自己紹介

千葉工業大学大学院 情報科学研究科 情報科学専攻 修士1年の井上 裕介と申します.
大学では主にメタヒューリスティクスに関する最適化アルゴリズムの研究に従事しております.
2023 年のサマーインターンから引き続き Sreake 事業部にて技術調査を行っております.

はじめに

サービスメッシュは,マイクロサービスアーキテクチャにおいて欠かせない通信管理の仕組みとして進化を続けています.

その代表的なソリューションである Istio は,2017年以降多くのユーザに利用されてきました.

2024年に Google Cloud は,従来の Anthos Service Mesh のサービス名を Cloud Service Mesh に変更し,提供を開始しました.

マネージドサービスメッシュの登場により,サービスメッシュの管理はこれまで以上にシンプルになる可能性が出てきました.

本稿では,Istio と Cloud Service Mesh の違いを掘り下げながら,特に「マネージドな」サービスメッシュにおける管理の簡素化やメリットについて詳しく解説します.

前提知識

ではまず最初に,サービスメッシュとは何かについて解説し,Cloud Service Mesh について紹介します.

サービスメッシュ

マイクロサービスアーキテクチャにおいて,各サービスは独立して動作し,サービス間は API を用いて互いに通信しながら機能します.

ここで,マイクロサービスにおけるサービスの内容には,主に次の2つに分類されます.

  • 機能ロジック (Functional Logic):
    アプリケーションが提供する「機能」を実現するための処理や実装
  • 非機能ロジック (Non-functional Logic):
    アプリケーションの「品質」を保証するために必要な処理や実装

マイクロサービスの開発について,図:マイクロサービスの実装 a. を例にとって解説します.

図 1: マイクロサービスの実装

アプリケーション開発者がマイクロサービスを開発する際,最も意識して開発すべき対象は機能ロジックです.

しかし,図のマイクロサービスでは,非機能ロジックであるトラフィック管理がひとつのサービスに内包されています.

ビジネスロジックと非機能ロジックが混在するマイクロサービスでは,次のような問題が発生します.

  • 多言語対応の複雑さ:
    マイクロサービスの開発言語が多様なため,言語ごとに非機能ロジックのライブラリを開発する必要がある
  • 特定のライブラリへの依存:
    マイクロサービスの特定のレイヤーの実装が,共有ライブラリに強く依存する
  • 責任範囲の曖昧さ:
    機能ロジックと非機能ロジックの境界が曖昧になり,開発チーム間での分業がしにくい状況

このような問題は,ビジネスロジックの開発速度を低下を招き,エンジニアの開発体験を悪化させます.

そこでサービスメッシュの出番です.

サービスメッシュ (Service Mesh) は,マイクロサービス同士のトラフィックを管理するための仕組みです.

CNCF (Cloud Native Computing Foundation) では,サービスメッシュを次のように説明しています.

サービスメッシュは,サービス間のトラフィック(つまり通信)を管理します.これにより,プラットフォームチームは,コードを変更することなく,クラスター内で実行されるすべてのサービスに信頼性,可観測性,セキュリティ機能を均一に追加できるようになります.

< 中略 >

サービスメッシュは,アプリコードに触れることなく,プラットフォームレイヤー上のすべてのサービスに信頼性,可観測性,セキュリティ機能を均一に追加します.あらゆるプログラミング言語と互換性があるため,開発チームはビジネスロジックの作成に集中できます.

引用: https://landscape.cncf.io/guide#orchestration-management–service-mesh

サービスメッシュは,主に次のような非機能ロジックを各マイクロサービスに対して横断的に配布します.

  • L4/L7 トラフィック管理
  • 証明書管理
  • 認証認可
  • テレメトリー作成
  • ブラックボックステスト
  • 回復性管理

サービスメッシュでは,各サービスにサイドカープロキシ (Sidecar proxy) と呼ばれる仲介役を配置し,サービス間の通信を制御・監視します.

このとき,プロキシはサービスに対して外付け機能として実装されます.

これはサイドカーモデル (Sidecar model) と呼ばれ,多くのサービスメッシュで採用されている実装方法です.

非機能ロジックのサイドカーと機能ロジックのビジネスロジックとは互いに独立しており,アプリケーション領域とインフラ領域のそれぞれのロジックを切り離すことができます.

図:マイクロサービスの実装 b. のように,サービスメッシュの導入後,マイクロサービスのビジネスロジックと非機能ロジックとを,コンテナという境界で明確に分業することができるようになりました.

これにより,アプリケーション担当はビジネスロジックの開発に集中できるようになり,インフラ担当はビジネスロジックに干渉することなく,安全に非機能ロジックの保守運用を行えるようになります.

これは,チーム全体の開発速度を向上させ,結果サービス全体のアジリティを向上することが期待されています.

Cloud Service Mesh

概要

Cloud Service Mesh は Istio を拡張した Google Cloud のマネージドサービスメッシュです.

Google Cloud の Compute Engine と Google Kubernetes Engine (GKE) Enterprise 環境の両方と,Google Cloud 外部との連携に対応しています.

Istio をベースとしながら,サービスメッシュの導入に伴う管理・監視・セキュリティの複雑さを軽減し,CloudNative な環境でより簡単に運用できるのが特徴です.

Cloud Service Mesh は,トラフィック管理やメッシュ テレメトリー,サービス間の通信の保護などのサービス提供を簡素化して,運用チームと開発チームのためにトイルを軽減します.Google のフルマネージド サービス メッシュを使用すると,複雑な環境を管理し,マイクロサービスのあらゆるメリットを享受できます.

引用: https://cloud.google.com/service-mesh/docs/overview?hl=ja#what_is

マネージドなサービスメッシュとは

Cloud Service Mesh は「マネージドなサービスメッシュ」という用語と共に紹介されています.

マネージドなサービスメッシュとは,一体どのようなものでしょうか.

Google Cloud が紹介する「マネージド」とは,サービスメッシュの運用に伴う管理作業をクラウド事業者が肩代わりする形のサービスを指します.

Cloud Service Mesh では,以下の点が管理されています.

  • コントロールプレーンの運用管理 (インストール・アップグレード・パッチ適用)
  • 監視,メトリクスの統合 (Cloud Monitoring, Logging, Trace)
  • IAM との統合によるセキュリティ強化
  • マルチクラウド・ハイブリッド環境での利用

複雑な運用になりがちな Istio の管理のほとんどを Google Cloud が負担するため,インフラエンジニアや SRE チームの作業負担を削減することが期待されます.

また,GKE Enterprise 環境では以前から asmcli を用いて Anthos Service Mesh を手動でインストールすることで,Google Cloud が提供する機能との連携が可能でした.

Cloud Service Mesh では,GKE Autopilot (以降 Autopilot) によるクラスタ作成時に,自動で Anthos Service Mesh のインストールを行なってくれます.

これにより,マイクロサービスアプリケーションのデプロイ,サービスメッシュのオートスケーリングなどの複雑な作業が,IaC や CI/CD パイプラインに簡潔に組み込まれます.

アーキテクチャ

Cloud Service Mesh は Istio API ではなく Google Cloud API を使用します.

この API は Mesh, Gateway, Route という3つの主要なリソースで構成されています.

  • Meshリソース:
    istio-proxy とプロキシレス gRPC クライアントのサービス間トラフィックの管理とセキュリティ構成に使用される (East-West サービス間トラフィック) istio-proxy とプロキシレス gRPC クライアントは,Mesh リソースの名前で識別されるサービスメッシュに結合することで,Cloud Service Mesh から構成を受け取る
  • Gatewayリソース:
    Istio Ingress Gatewayとして機能する istio-proxy のトラフィック管理とセキュリティ構成に使用され,外部クライアントがサービスメッシュに接続可能となる (North-South サービス間トラフィック) Route リソースによって参照され,対応する Gateway 構成に含まれるルートが追加される
  • Routeリソース:
    HTTPRoute, GRPCRoute, TCPRoute, TLSRoute の4種類があり,サービスにルーティングを設定するために使用される これらの Route リソースは,1つ以上の Mesh リソースまたは Gateway リソースを参照し,対応する構成にルートを追加する Route リソースは,ルーティングの最終的な宛先として1つ以上のバックエンドサービスリソース (MIG (Management Instance Group), NEG (Network Endpoint Group)) を参照する形で作成される
図 2: Cloud Service Mesh のリソースと Cloud API の流れ

Istio 単体では, istio-init コンテナや istio-cni ノードエージェントがトラフィックリダイレクトの役割を担っていました.

Cloud Service Mesh では,Mesh リソースや Gateway リソースを使用することで,関連するすべてのトラフィックが自動的にインターセプトされ,トラフィックは istio-proxy によって処理されます.

Route リソースは宛先情報に基づいてルーティングし,最終的に NEG が指定するエンドポイントへトラフィックが転送されます.

図 3: サービス ルーティング API リソースのユースケース
引用: https://cloud.google.com/service-mesh/docs/service-routing/service-routing-overview?hl=ja#use-cases

Cloud Service Mesh では,Istio が担う一部の役割は Google Cloud のマネージドサービスとして統合され,サービスメッシュをより透過的に提供していると考えられます.

では,NEG とは一体どのようなバックエンドサービスリソースなのでしょうか.

図 4: Kubernetes API オブジェクトと Compute Engine オブジェクトの対応関係
引用: https://cloud.google.com/kubernetes-engine/docs/how-to/standalone-neg?hl=ja#overview

Google Cloud の VPC (Virtual Private Cloud) ネットワークでは,Kubernetes リソースに対して Network Endpoint を割り当てます.

プロビジョニングされたすべての Pod には Network Endpoint というオブジェクトが付与され,Pod を管理する Service には Network Endpoint Group (NEG) というオブジェクトが付与されます.

こうすることで,Pod や Service を Google Cloud のリソースとして扱うことが可能となります.

NEG は Google Cloud の VPC ネットワークで次の役割を担います.

  • トラフィックのバックエンドエンドポイント
  • コンテナネイティブなロードバランシングのサポート
  • FQND ベースのサービスディスカバリ

NEG は,インターセプトされた後のトラフィックが最終的にどこにルーティングされるかを定義するバックエンドとして機能します.

このように,MeshGateway がトラフィックのインターセプトと大まかなスコープを定義し,Route が具体的なルーティングポリシーを,そして NEG がそのルーティングの具体的な終点を提供することで,Cloud Service Mesh は高度なトラフィック管理機能を実現しています.

マネージドコントロールプレーンにてサービスディスカバリを行なっているため,管理者は Pod にサイドカーが注入されていることを気にするだけで良いのです.

※ 本稿では簡単のため Zonal NEG, Internet NEG, Standalone NEG を分別せずに説明しました.より詳細な解説は参考資料 7参考資料 8及び参考資料 9を参照して下さい.

次章では実際に GKE Enterprise 環境で Cloud Service Mesh を構築してみましょう.

Cloud Service Mesh のプロビジョニングと動作確認

ここからは,Cloud Service Mesh コントロールプレーンを GKE のクラスタにインストールしていきます.

Cloud Service Mesh をクラスタにインストールするには,まず表 1のロールがついていることを確認しましょう.

ここではロールの付与に関しては紹介を省きますので,こちらで詳細を確認してください.

ロール名ロール ID付与する場所説明
GKE Hub 管理者roles/gkehub.adminFleet ProjectGKE Hub と関連リソースに対する完全アクセス権.
Service Usage 管理者roles/serviceusage.serviceUsageAdminFleet Projectサービス状態の有効化,無効化,検査,オペレーションの検査,ユーザ プロジェクトの割り当てと請求の利用が可能な権限.
CA サービス管理者 β版roles/privateca.adminFleet Projectすべての CA サービスのリソースへの完全アクセス権.
表 1: Cloud Service Mesh のインストールに必要なロール

Cloud Service Mesh の環境構築に使用するソフトウェアについて,表 2に掲載するものを使用しました.

OSmacOS Sequoia 15.5 arm64
Shell (zsh)5.9
gcloudGoogle Cloud SDK 524.0.0
bq 2.1.17
core 2025.05.23
gcloud-crc32c 1.0.0
gke-gcloud-auth-plugin 0.5.10
gsutil 5.34
kubectlClient Version: v1.33.1
Kustomize Version: v5.6.0
Server Version: v1.32.4-gke.1106006
istioctlclient version: 1.26.0
表 2: 検証で使用したソフトウェア

本稿の検証は以下の GitHub リポジトリを使用して進めていきます.

セットアップ

検証を行う前準備として,gcloud などのツールのインストールや環境変数の定義を行います.

gcloud CLI をインストールする

本稿で使用する GitHub のリポジトリをクローンし,ディレクトリへ移動

csm-env.sh を実行して環境変数の設定を行う

sudo chmod +x csm-env.sh
./csm-env.sh
source asmcli.env
環境変数名概要
FLEET_PROJECT_IDFleet 登録先の GCP プロジェクト ID
FLEET_PROJECT_NUMBER上記 Fleet プロジェクトのプロジェクト番号
CLUSTER_PROJECT_IDGKE クラスタを作成する GCP プロジェクト ID (例: csm-bookinfo )
NETWORK_PROJECT_IDネットワーク (VPC) を所有する GCP プロジェクト ID
FIREWALLファイアウォール名.<NETWORK_PROJECT_ID>-fw という形式で定義
REGIONGKE クラスタのリージョン (例:asia-northeast1 )
LOCATIONGKE クラスタのロケーション (例:asia-northeast1-a )
CONTEXTkubectlasmcli 用の GKE クラスタのコンテキスト名
HPATHASM 関連ファイルで使う Docker ホームパス
OUTPUT_DIR出力ファイルの保存先ディレクトリ
CREDENTIAL_PATHGCP 認証情報ファイルのパス
CLOUD_DNS_IDCloud DNS ゾーンの ID
DESCRIPTIONDNS ゾーンの説明
表 3: 環境変数の概要

プロジェクト ID $FLEET_PROJECT_ID の認証を行い,Google アカウントでログイン

gcloud auth login --project $FLEET_PROJECT_ID

gcloud CLI にインストールされているコンポーネントの更新を行う

gcloud components update

Google Cloud CLI をセットアップ

gcloud components install gke-gcloud-auth-plugin

~/.zshrc に以下の項目を追加し更新

export PATH=$PATH:~/google-cloud-sdk/bin source ~/.zshrc

インストールの確認

gke-gcloud-auth-plugin --version

結果

Kubernetes v1.28.2-alpha+000000000000000000000000000

これで準備が整いました.

次章ではクラスタの作成を行います.

Cloud Service Mesh 有効なクラスタの作成

ここからは Cloud Service Mesh コントロールプレーンがインストールされたクラスタを作成していきます.

csm ディレクトリへ移動する

mesh.yaml ファイルを作成する

echo "management: automatic" > mesh.yaml

Cloud Service Mesh のフリート機能を有効にする

gcloud container fleet mesh enable --project $FLEET_PROJECT_ID \
	--fleet-default-member-config mesh.yaml

結果

Waiting for Feature Service Mesh to be created...done. 

クラスタの作成を行う

gcloud container clusters create-auto $CLUSTER_PROJECT_ID \
	--fleet-project $FLEET_PROJECT_ID \
	--location $REGION

クラスタの作成が完了したら作成されたクラスタを確認する

gcloud container clusters list

結果(NUM_NODES が空なのは Autopilot の仕様)

NAME                  LOCATION         MASTER_VERSION      MASTER_IP        MACHINE_TYPE  NODE_VERSION        NUM_NODES  STATUS
<CLUSTER_PROJECT_ID>  asia-northeast1  1.32.4-gke.0000000  XXX.XXX.XXX.XXX  e2-small      1.32.4-gke.0000000             RUNNING

kubectl が作成したクラスタを参照するようにクレデンシャルを取得する

gcloud container clusters get-credentials $CLUSTER_PROJECT_ID \
  --location $REGION \
  --project $FLEET_PROJECT_ID

クラスタの起動を確認

kubectl config current-context

結果

gke_<FLEET_PROJECT_ID>_<REGION>_<CLUSTER_PROJECT_ID>

次のコマンドを実行してクラスタの Workload Identity プール を一覧取得し,Workload Identity 連携が有効になったことを確認する

gcloud container clusters describe $CLUSTER_PROJECT_ID \
  --location $REGION \
  --format="value(workloadIdentityConfig.workloadPool)"

以下の値が返ってくれば有効である

<FLEET_PROJECT_ID>.svc.id.goog

クラスタがフリートに登録されていることを確認する

gcloud container fleet memberships list --project $FLEET_PROJECT_ID

結果

NAME                  UNIQUE_ID                             LOCATION
<CLUSTER_PROJECT_ID>  00000000-0000-0000-0000-000000000000  <REGION>

Cluster の Mesh API を有効化

gcloud services enable mesh.googleapis.com --project $FLEET_PROJECT_ID

ローカルからコントロールプレーンがプロビジョニングされていることを確認する

gcloud container fleet mesh describe --project $FLEET_PROJECT_ID

以下のような出力が表示される

~~~
membershipSpecs:
  projects/000000000000/locations/asia-northeast1/memberships/csm-bookinfo:
    mesh:
      management: MANAGEMENT_AUTOMATIC
    origin:
      type: FLEET
membershipStates:
  projects/000000000000/locations/asia-northeast1/memberships/csm-bookinfo:
    servicemesh:
~~~
      controlPlaneManagement:
        details:
        - code: REVISION_READY
          details: 'Ready: asm-managed'
        implementation: TRAFFIC_DIRECTOR
        state: ACTIVE
      dataPlaneManagement:
        details:
        - code: OK
          details: Service is running.
        state: ACTIVE
    state:
      code: OK
      description: 'Revision ready for use: asm-managed.'
~~~

membershipStatesimplementation を確認すると TRAFFIC_DIRECTOR と書かれている

https://cloud.google.com/service-mesh/docs/check-control-plane-implementation?hl=ja

Web コンソールを開き,クラスタから $CLUSTER_PROJECT_ID を選択し,機能欄の一番下の項目を確認する

プロビジョニング済み とあれば成功

これで Cloud Service Mesh が有効なクラスタの用意が完了しました.

Istio Ingress Gateway のインストール

最後に外部からサービスメッシュへアクセスするために Istio Ingress Gateway をクラスタにデプロイする必要があります.

csm ディレクトリで引き続き作業

以下のコマンドで istio-system Namespace を作成

kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: istio-system
  annotations:
    mesh.cloud.google.com/proxy: '{"managed":"true"}'
  labels:
    istio-injection: enabled
EOF

anthos-service-mesh-packages リポジトリをクローンする

git clone https://github.com/GoogleCloudPlatform/anthos-service-mesh-packages.git

istio-system Namespace に Istio Ingress Gateway をデプロイする

kubectl apply -n istio-system -f ./anthos-service-mesh-packages/samples/gateways/istio-ingressgateway

istio-ingressgatewayistio-system Namespace に正常に適用され istio=ingressgateway ラベルがあるかを確認

kubectl get pod -n istio-system -l istio=ingressgateway --show-labels | grep "istio=ingressgateway"

結果
3つの Pod が作成されており,STATUSRunning であることを確認する

NAME                                    READY   STATUS    RESTARTS   AGE
istio-ingressgateway-0000000000-00000   1/1     Running   0          2m40s
istio-ingressgateway-1111111111-11111   1/1     Running   0          2m41s
istio-ingressgateway-2222222222-22222   1/1     Running   0          2m41s

istio-ingressgateway Service に EXTERNAL-IP が割り振られているか確認

kubectl get svc -n istio-system

結果

NAME                   TYPE           CLUSTER-IP        EXTERNAL-IP       PORT(S)                                      AGE
istio-ingressgateway   LoadBalancer   XXX.XXX.XXX.XXX   XXX.XXX.XXX.XXX   15021:30242/TCP,80:32325/TCP,443:31116/TCP   12m

これで通常の Istio を用いた Kubernetes クラスタと,ほぼ同様のサービスメッシュ環境が構築できました.

次章では,実際にマイクロサービスアプリケーションをデプロイしてみましょう.

サンプルアプリ Bookinfo のインストール

ここからは,Istio が提供するサンプルアプリ Bookinfo Application をクラスタにデプロイします.

図 5: Bookinfo Application
引用: https://istio.io/latest/docs/examples/bookinfo/

Bookinfo で提供されるマイクロサービスは以下の通りです.

  • productpage:
    details と reviews マイクロサービスを呼び出して,ページに情報を入力する
    • details:
      書籍情報が含まれる
    • reviews:
      書評が含まれます.また,ratings マイクロサービスを呼び出す
    • ratings:
      書評に伴う書籍ランキング情報が含まれる

reviews のマイクロサービスには次の 3 つのバージョンがある

  • Reviews v1: 
    ratings サービスを呼び出さない
  • Reviews v2: 
    ratings サービスを呼び出し,各評価を 1~5 個の黒色の星で表示
  • Reviews v3:
    ratings サービスを呼び出し,各評価を 1~5 個のオレンジ色の星で表示

本章の目標は,ブラウザ上のダッシュボードからマイクロサービスのトラフィックを確認することとします.

では早速アプリケーションのデプロイを行っていきましょう.

bookinfo ディレクトリへ移動する

デフォルトのインジェクションラベルを Namespace に適用する

kubectl label namespace default istio.io/rev- istio-injection=enabled --overwrite

istio-injection ラベルがついた Namespace を確認

kubectl get ns --show-labels -l="istio-injection"

結果

NAME           STATUS   AGE   LABELS
default        Active   35m   istio-injection=enabled,kubernetes.io/metadata.name=default
istio-system   Active   31m   istio-injection=enabled,kubernetes.io/metadata.name=istio-system

最新版の Istio をダウンロードする 本稿では istio-1.26.0 環境で検証を行う ※ バージョンを指定する場合は ISTIO_VERSION=<version number> sh - と記述する

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

以下のコマンドを実行して Bookinfo アプリをデプロイする

kubectl apply -f ./istio-*/samples/bookinfo/platform/kube/bookinfo.yaml

アプリケーションがデプロイできたか確認する

kubectl get pods,services

結果

NAME                                  READY   STATUS    RESTARTS   AGE
pod/details-v1-84766dc95b-k6h2h       2/2     Running   0          53s
pod/productpage-v1-77549cbd67-bmlgk   2/2     Running   0          50s
pod/ratings-v1-b68c7d664-n9xdq        2/2     Running   0          53s
pod/reviews-v1-cd8d4db96-7rhdv        2/2     Running   0          52s
pod/reviews-v2-759fd6876d-8bq9h       2/2     Running   0          51s
pod/reviews-v3-f98496d4-d6mdn         2/2     Running   0          51s

NAME                  TYPE        CLUSTER-IP        EXTERNAL-IP   PORT(S)    AGE
service/details       ClusterIP   XXX.XXX.XXX.XXX   <none>        9080/TCP   55s
service/kubernetes    ClusterIP   XXX.XXX.XXX.XXX   <none>        443/TCP    35m
service/productpage   ClusterIP   XXX.XXX.XXX.XXX   <none>        9080/TCP   51s
service/ratings       ClusterIP   XXX.XXX.XXX.XXX   <none>        9080/TCP   55s
service/reviews       ClusterIP   XXX.XXX.XXX.XXX   <none>        9080/TCP   53s

ClusterIP の DNS 解決とサービスメッシュ通信が成功しているかを Ratings Pod から確認

kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"

結果

<title>Simple Bookstore App</title>

bookinfo-gateway.yaml に以下の変更を加える

apiVersion: networking.istio.io/v1beta1 # <- v1 から v1beta1 へ変更
kind: Gateway
metadata:
  name: bookinfo-gateway
  namespace: default # <- default Namespace を追加
spec:
~~~
  servers:
  - port:
      number: 80 # <- 8080 から 80 へ変更
~~~
---
apiVersion: networking.istio.io/v1beta1 # <- v1 から v1beta1 へ変更
kind: VirtualService
metadata:
  name: bookinfo
  namespace: default # <- default Namespace を追加
~~~
  • apiVersionv1 から v1beta1 に変更
  • metadata.namespace.default を追加
  • Gateway マニフェストの spec.servers.port.number を 8080 から 80 へ変更
    ※ 2025年7月現在, Cloud Service Mesh のコントロールプレーンである Traffic Director の API バージョンは v1beta1 までしか対応しておりません.
    https://cloud.google.com/service-mesh/docs/supported-features-managed?hl=ja#sidecar

Bookinfo アプリの Gateway をデプロイする

kubectl apply -f ./istio-*/samples/bookinfo/networking/bookinfo-gateway.yaml

Gateway と Virtual Service の確認

kubectl get gw,virtualservice

結果

NAME                                           AGE
gateway.networking.istio.io/bookinfo-gateway   60s

NAME                                          GATEWAYS               HOSTS   AGE
virtualservice.networking.istio.io/bookinfo   ["bookinfo-gateway"]   ["*"]   60s

これでクラスタの作成からサンプルアプリ Bookinfo のデプロイまでが完了しました.

Cloud Service Meshの動作確認

続いて,Bookinfo アプリを使って Cloud Service Mesh の動作確認を行なっていきましょう.

ターミナルから Bookinfo へリクエストを発生させ,サービスメッシュのトラフィックを Google Cloud のサービスメッシュダッシュボードから様子を確認できます.

Bookinfo アプリケーションにアクセスする

アプリケーションへのアクセス方法について解説します.

INGRESS_HOSTGATEWAY_URL にそれぞれ値を代入する

export INGRESS_HOST=$(kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
export GATEWAY_URL=$INGRESS_HOST:80
echo "http://${GATEWAY_URL}/productpage"

Bookinfo アプリにリクエストを送信 ※ 更新に1分程度かかるため,繋がらない場合は少し待ってから再度実行してください

curl -I "http://${GATEWAY_URL}/productpage"

結果

HTTP/1.1 200 OK
server: istio-envoy
date: Mon, 02 Jun 2025 09:21:08 GMT
content-type: text/html; charset=utf-8
content-length: 15072
vary: Cookie
x-envoy-upstream-service-time: 226

http://<GATEWAY_URL>/productpage にブラウザからアクセスする

通常の Bookinfo は v1 , v2 , v3 の3つのサービスが同時にデプロイされている バージョンの差異は Book Reviews の星を確認することで判別できる

  • v1: 星が表示されない
  • v2: 黒い星が表示される
  • v3: オレンジ色の星が表示される

一旦お疲れ様でした 🙌

順調に進んでいれば,ブラウザからクラスタにデプロイした Bookinfo アプリケーションへ到達できたかと思います.

では,サービスメッシュの状態を Google Cloud のダッシュボードから確認してみましょう.

可視化したサービスメッシュのトラフィックの様子を確認する

ここからは,Google Cloud のマネージドサービスメッシュが提供する機能について紹介していきます.

また,本稿では簡単な検証として次の項目を行います.

  • すべてのマイクロサービスのトラフィックを確認する
  • DestinationRule を追加し,加重ルーティングが行われる様子を確認する

では,検証に入っていきます.

1秒間隔で Bookinfo にローカルからリクエストを送信する

while :; do curl -s "http://${GATEWAY_URL}/productpage" | grep -o "<title>.*</title>"; sleep 1; done

ブラウザでサービスメッシュのダッシュボードを開き,トラフィックの様子を確認する

サービスのノードにカーソルをホバーするとエッジの統計情報を表示できる

さらにノードをホバー中に Expand タブをクリックすることで Deployment , Pod までノードの詳細を展開できる

トポロジのノードをクリックすると,リストビューに詳細カードが表示される

より詳細な情報はリストビューの ダッシュボードに移動 から確認できる ここでは productpage の詳細を確認する

概要

概要 について確認すると以下のような画面に遷移する

連携サービス

連携サービス ではトポロジ指標を表示し,サービス間の送受信アクセスによる通信の暗号化などをリスト化して表示される

  • 緑色: mTLS による暗号通信が行われている
  • 黄色: 暗号化 (mTLS) と平文の混在
  • 赤色: 平文による通信が行われている

1秒あたりのリクエスト数

エラー率

レイテンシ (50%, 95%, 99%)

指標

指標 ではリクエストなどのデータを時系列チャートで確認できる

インフラストラクチャ

インフラストラクチャ ではインスタンスのメトリクスなどを時系列チャートで確認できる

トラフィック

トラフィック では各サービス間通信におけるトラフィックの指標やサービスの詳細を確認できる

その他

セキュリティ連携サービス と同様のページが表示される

リソース では対象の Service に関係するリソース (クラスタ,Gateway etc) の設定ファイルを参照できる

トラフィックルーティング

Bookinfo には Istio が提供する機能をテストできるいくつかのタスクが提供されています.

ここではタスクの一つであるリクエストルーティングを行い,トラフィックの様子を確認します.

⚠️ 以下で使用するすべてのマニフェストについて,apiVersion: networking.istio.io/v1 とある部分を apiVersion: networking.istio.io/v1beta1 に変更してから実行して下さい.

アプリケーションへのルートルールを設定し,各サービスのバージョンを指定する

kubectl apply -f ./istio-*/samples/bookinfo/networking/destination-rule-all.yaml

DestinationRule 設定を確認する

kubectl get destinationrules

結果

NAME          HOST          AGE
details       details       17s
productpage   productpage   19s
ratings       ratings       18s
reviews       reviews       18s

サービスへのアクセスを v1 のみに制限する

kubectl apply -f ./istio-*/samples/bookinfo/networking/virtual-service-all-v1.yaml

ダッシュボードからトポロジを確認する

v1 Service に 100% トラフィックが送信されていることが確認できる

トラフィック から確認すると,v1 Service にアクセスが集中している様子がよくわかる

DestinationRule を削除する

kubectl delete -f ./istio-*/samples/bookinfo/networking/virtual-service-all-v1.yaml

このように,DestinationRule を定義することで Cloud Service Mesh 環境でも Istio と同様にアプリケーションへの加重ルーティングを手軽に行うことができ,その様子をダッシュボード上から確認することができました.

クリーンアップ

使い終わった不要なクラスタは削除しましょう.

csm ディレクトリにてアプリケーションを削除する

kubectl delete -f ./istio-*/samples/bookinfo/networking/destination-rule-all.yaml
kubectl delete -f ./istio-*/samples/bookinfo/platform/kube/bookinfo.yaml
kubectl delete -f ./istio-*/samples/bookinfo/networking/bookinfo-gateway.yaml

csm-handson ディレクトリへ戻り,クラスタを削除する

gcloud container clusters delete $CLUSTER_PROJECT_ID --location $REGION

csm-handson ディレクトリで検証で使用した環境変数を削除する

source ./csm-env.sh -cleanup

Cloud Service Mesh の仕様と使用する際の勘所について

お疲れ様でした! 👏

ここまで,Cloud Service Mesh を前提としたクラスタの構築からテスト用のアプリケーションのデプロイまで,一通りの検証を行いました.

この章では,私が Cloud Service Mesh を調査する過程で遭遇した疑問や,使用する際の課題について紹介します.

Istio データプレーンと Traffic Director コントロールプレーンによるマネージドなサービスメッシュの構成

Istio 環境において, istio-init コンテナの主な役割は,Pod 内のネットワークトラフィック (インバウンドおよびアウトバウンド) を Envoy サイドカープロキシにリダイレクトするための iptables ルールを設定することでした.

これには,Pod が NET_ADMINNET_RAW といった特権的な Kubernetes RBAC 権限を持つ必要があります.

図 6: istio-cni ノードエージェント
引用: https://istio.io/latest/docs/setup/additional-setup/cni/

istio-cni ノードエージェントは, istio-init コンテナが特権を有するため,これを回避するために提案された後発のプラグインであり,主に Pod のトラフィックを istio-proxy に流すために iptables のセットアップなどを行います.

istio-cni ノードエージェントは,各 Kubernetes ノード上で特権を持つ単一の DaemonSet として動作し,Pod ごとに特権コンテナをデプロイするのではなく,ノードレベルで chained CNI プラグインをインストールします.

このプラグインが,Pod のネットワークセットアップフェーズで iptables ルールを設定し,トラフィックを istio-proxy にリダイレクトします.

これにより,ユーザやワークロードが特権を持つ必要がなくなります.

しかし,GKE Autopilot 環境では Autopilot による管理により,kube-system などに対する管理者側の操作を一切禁止しています.

これにより,一部のシステムコールを使用する CRD (Custom Resource Definitions) のインストールを妨害してきます.

ここで一つ疑問になるのが,「一体 GKE Enterprise 環境の Pod はどのように通信を行なっているのか」です.

なぜなら, istio-cni ノードエージェントが存在しないということは, iptables の設定は行われません.

これは非常に奇妙な状況であることが分かります.

この奇妙なルーティングの正体は,冒頭で紹介した Google Cloud の NEG が関係しています.

NEG は Google Cloud の VPC ネットワークにおいて,バックエンドエンドポイントとして機能します.

Google Cloud では Pod に紐づいたエンドポイントの管理を NEG が担うことで,インスタンスの iptables を介さずにマネージドなルーテイングを提供することができます.

図 7: Ingress support with instance groups vs. with network endpoint groups.
引用: https://cloud.google.com/blog/products/containers-kubernetes/container-native-load-balancing-on-gke-now-generally-available?hl=en

Cloud Service Mesh では, Istio のデータプレーンによって実現していた Envoy によるルーティング機能が,NEG などの Google Cloud のネイティブコンポーネントとして統合されています.

具体的には,Istio カスタムリソースである Gateway , VirtualService , DestinationRule が主体となって istio-proxy (Envoy) の設定の抽象化とロードバランシングを提供します.

図 8: Cloud Service Mesh サービスメッシュの Istio データプレーンと NEG の処理の流れ

Google Cloud が提供するコントロールプレーンには Traffic Director と istiod があり,すべての istio-proxy を制御し,サービスメッシュ全体のプロキシの管理・監視から証明書の管理などを担います.

Traffic Director は NEG を介して Pod をエンドポイントとして抽象化し,サイドカープロキシにルーティングに関する情報を配布することで,高度なルーティングを可能にしています.

以下の表 4は, Istio API と Google Cloud API ,それぞれが Cloud Service Mesh で利用可能な機能について比較を行なったものです.

項目Istio API リソースGoogle Cloud API リソース範囲割り当てと上限上限
トラフィック ルーティングVirtualServiceHTTPRouteTCPRouteTLSRouteグローバルHTTPRoute の割り当てTCPRoute の割り当てTLSRoute の割り当てサービスポートごとに 1 つ,Istio VirtualService HTTPRoute,TCPRoute,TLSRoute ごとに 1 つ.
サービス表現(ルート / ポリシー アタッチメント用)ServiceServiceEntryBackendServiceグローバルBackendService の割り当てサービスポートごとに 1 つ(Istio ServiceEntry を含む).
ワークロードのプロパティ(IP:port,ローカリティなど)ServiceServiceEntryNetworkEndpointGroupゾーンNetworkEndpointGroup の割り当てサービスポート,ゾーンごとに 1 つ.リージョン GKE クラスタでは,クラスタのノードが少なくとも 1 つあるすべてのゾーンに,特定のサービスポートの NetworkEndpointGroup が作成されます.
ワークロードの健全性のモニタリングサービスHealthCheckグローバルHealthCheck の割り当てGKE クラスタごとに 1 つ.
ワークロード ポリシーの接続ポイントPeerAuthenticationAuthorizationPolicyRequestAuthentication EnvoyFilterEndpointPolicyグローバルEndpointPolicy の割り当てサービスポートとワークロード ポリシーごとに 1 つ.
認証PeerAuthenticationClientTlsPolicyServerTlsPolicyグローバルClientTlsPolicy の割り当てServerTlsPolicy の割り当てサービスポートごとに 1 つの ClientTlsPolicy.TLS Gateway ごとに 1 つの ServerTlsPolicy.
承認AuthorizationPolicyHttpFilterグローバルHttpFilter の割り当てIstio AuthorizationPolicy ごとに 1 つ.
ゲートウェイゲートウェイゲートウェイグローバルGateway の割り当てIstio Gateway サーバーポートごとに 1 つ.
トラフィック分散ポリシーGCPTrafficDistributionPolicyServiceLbPolicyグローバルServiceLbPolicy の割り当てGCPTrafficDistributionPolicy ごとに 1 つ.
表 4: マネージド Cloud Service Mesh に対する Istio API
引用: https://cloud.google.com/service-mesh/docs/understand-api-resources?hl=ja#my-heading

この表から, Istio API と Google Cloud API は一対一に対応した API が存在し, Google Cloud では Traffic Director によってサービスメッシュを実現しています.

では, Traffic Director によって管理される istio-proxy を確認してみましょう.

動作中の ratings-v1 Pod をキルし,Deployment により再度 Pod がデプロイされたことを確認する

kubectl delete pod ratings-v1-000000000-00000 -n default
kubectl get pods | grep "ratings-v1"

結果

pod "ratings-v1-000000000-00000" deleted
ratings-v1-111111111-11111        0/2     PodInitializing   0          6s

Pod の Events ログを確認する

kubectl describe pod/ratings-v1-111111111-11111 | grep "Events" -A 20

結果

Events:
  Type     Reason                             Age                    From                                   Message
  ----     ------                             ----                   ----                                   -------
  Normal   LoadBalancerNegNotReady            1m36s                  neg-readiness-reflector                Unable to determine the pod's node name.
  Normal   Scheduled                          1m36s                  gke.io/optimize-utilization-scheduler  Successfully assigned default/ratings-v1-xxxxxxxx-xxxx4 to gk3-<CLUSTER_PROJECT_ID>-nap-xxxxxxxx-xxxxxxxx-xxxx
  Normal   LoadBalancerNegNotReady            1m36s (x2 over 7m36s)  neg-readiness-reflector                Waiting for pod to become healthy in at least one of the NEG(s): [k8s1-xxxxxxxx-default-ratings-9080-xxxxxxxx]
  Normal   Pulled                             1m35s                  kubelet                                Container image "gcr.io/gke-release/asm/proxyv2:1.20.8-asm.33-distroless" already present on machine
  Normal   Created                            1m35s                  kubelet                                Created container: istio-validation
  Normal   Started                            1m35s                  kubelet                                Started container istio-validation
  Normal   Pulled                             1m34s                  kubelet                                Container image "docker.io/istio/examples-bookinfo-ratings-v1:1.20.3" already present on machine
  Normal   Created                            1m34s                  kubelet                                Created container: ratings
  Normal   Started                            1m34s                  kubelet                                Started container ratings
  Normal   Pulled                             1m34s                  kubelet                                Container image "gcr.io/gke-release/asm/proxyv2:1.20.8-asm.33-distroless" already present on machine
  Normal   Created                            1m34s                  kubelet                                Created container: istio-proxy
  Normal   Started                            1m34s                  kubelet                                Started container istio-proxy
  Warning  Unhealthy                          1m33s                  kubelet                                Readiness probe failed: Get "http://xxx.xxx.xxx.xxx:15021/healthz/ready": dial tcp xxx.xxx.xxx.xxx:15021: connect: connection refused
  Normal   LoadBalancerNegWithoutHealthCheck  1m31s                  neg-readiness-reflector                Pod is in NEG "Key{\"k8s1-xxxxxxxx-default-ratings-9080-xxxxxxxx\", zone: \"asia-northeast1-c\"}". NEG is not attached to any BackendService with health checking. Marking condition "cloud.google.com/load-balancer-neg-ready" to True.

出力結果から, istio-proxyistio-validation の存在が確認され, Traffic Director によってサイドカーのプロビジョニングが行われたことがわかります.

Events ログの内容を詳しく見てみましょう.

はじめに ratings-v1 Pod が起動すると,その Pod の IP アドレスとポートが,対応する NEG にエンドポイントとして動的に登録されます.

このとき, neg-readiness-reflector は作成された Pod を監視対象として認識します.

次に neg-readiness-reflector は, Pod のコンテナ (この場合はratingsistio-proxy) が起動し,Kubernetes の Readiness Probe が成功するのを待ちます.

そして, Pod の Readiness Probe が成功すると, neg-readiness-reflector は Pod に対して cloud.google.com/load-balancer-neg-ready Condition を True に設定します.

このことから,Traffic Director は一部の Istio データプレーンと連携し,サービスメッシュの構成には Cloud API を使用して Cloud Service Mesh を構成していることがわかるかと思います.

サービスメッシュの Gateway として Istio Ingress Gateway を使用する場合の注意点

サービスメッシュにアクセスするには Gateway を必要とします.

Istio サービスメッシュに外部からアクセスする主要な方法は次の2種類があります.

Gateway API は動的なインフラストラクチャの展開と高度なトラフィックルーティングを提供する API のグループです.

今回は Gateway API は使用しませんでしたが,付録にて Gateway API を使用した Gateway のデプロイ方法が記載しています.

では Istio Ingress Gateway をデプロイする方法について見ていきましょう.

デプロイする手段はは主に二通りの方法があります.

まず,Anthos Service Mesh のリポジトリからデプロイする方法についてです.

本稿では Anthos Service Mesh のリポジトリをローカルのワークスペースにクローンし,kubectl コマンドを使用して istio-system Namespace に適用しました.

本来は asmcli コマンドを使用して Anthos Service Mesh をクラスタにインストールした際に,ローカルにリポジトリがクローンされます.

しかし,手動で行なった場合も問題なくクローンからの Gateway のデプロイが可能です.

もう一つの方法として,istioctl を使ってデプロイする方法があります.

おそらくほとんどの方は Istio をクラスタにインストールした際,自動的に istio-system Namespace に istio-ingressgateway がデプロイされていた,という場合が多いのではないでしょうか.

しかし,この方法で Autopilot 環境にインストールしようとすると,前述の通り Autopilot の制限によりうまくいきません ( istioctl を使用したデプロイ方法については付録に記載しています).

仮にインストールに成功したとしても,公式の想定では istiod はクラスタに存在せず,代わりに Traffic Director がコントロールプレーンとして動作するため,ダッシュボード上に Service が表示されないなどの不具合が生じます.

なお,6月時点での公式ドキュメントの紹介では Istio Ingress Gateway に関して特に言及がありませんでした.

しかし,7月11日の更新にて,公式ドキュメントに Istio Ingress Gateway のデプロイに関するページが追加されました.

サンプルアプリの Gateway のデプロイ方法について紹介されているので,本稿と合わせて読んでみてください.

まとめ

本稿では, Cloud Service Mesh の基本的な構築方法について解説しました.

istioctlasmcli などを一切使わずにサービスメッシュを構築可能であり,その手軽さが魅力的でした.

一方で,通常の Istio ベースの環境とは大きく異なる点がいくつか存在し,仕様の違いを理解するのに時間が必要でした.

Autopilot の登場により, Anthos Service Mesh を手動インストールする作業から解放されたことは喜ばしい反面, Anthos Service Mesh で可能だった柔軟な設定が Autopilot により制限されてしまったのは非常に残念です.

また,Istio のデータプレーンをそのまま使用することができるため,既存のサービスメッシュの移行作業がスムーズに実行可能でした.

一方で, 対応しているコントロールプレーンの API バージョンが v1beta1 までしか対応していない点や, Istio が提供する Traffic Policy や DNS Proxy といった一部の機能が Traffic Director では未実装である点が,不便と感じました.

これらの機能が今後どのようにサポートされていくのか注目です.

必要な最低限のモニタリングツールや GUI は Google Cloud がダッシュボード上で提供してくれるため,サービスメッシュの導入の敷居はそこまで高くないという印象でした.

次回は「実践編」ということで,Istio が得意とするトラフィック管理により注目し,Cloud Service Mesh 上でのルーティング制御について動作検証を行います.

その教材として,日本最大級の CloudNative 関係のテックカンファレンス「CloudNative Days」の実行委員会が提供する「一日で学ぶクラウドネイティブ技術実践ハンズオン」の Chapter Istio の内容を Cloud Service Mesh で再現したいと思います.

付録

Gateway API を使用したサービスメッシュへの接続

「テストアプリ Bookinfo のインストール.9」にて,Istio Ingress Gateway ではなく gateway-api/bookinfo-gateway.yaml を使用する

kubectl apply -f ./istio-*/samples/bookinfo/gateway-api/bookinfo-gateway.yaml

INGRESS_HOSTGATEWAY_URL にそれぞれ値を代入する

export INGRESS_HOST=$(kubectl get gtw bookinfo-gateway -o jsonpath='{.status.addresses[0].value}')
export GATEWAY_URL=$INGRESS_HOST:80
echo "http://${GATEWAY_URL}/productpage"

バックエンドサービスの3つのバージョンを定義する

kubectl apply -f ./istio-*/samples/bookinfo/platform/kube/bookinfo-versions.yaml

Autopilot 環境で Istio ベースのサービスメッシュを構築したい場合

Autopilot 環境下では,`istio-cni のインストールができないため,基本的には Anthos Service Mesh (旧 Traffic Director) での動作を基本とします.

しかし,セキュリティリスクの観点から非推奨ではありますが,istioctl を使用してインストールする方法があるため,簡単に紹介します.

Cloud Service Mesh のフリート機能を有効にした後,クラスタの作成を行う

gcloud container clusters create-auto $CLUSTER_PROJECT_ID \
	--fleet-project $FLEET_PROJECT_ID \
	--location $REGION \
  --workload-policies=allow-net-admin

--workload-policies=allow-net-admin は GKE バージョン 1.27 以降のクラスタに適応される.セキュリティ機能の一つである NET_ADMIN capability の許可を行う.要するに特権コンテナの作成を許可する操作である (参考資料 11を参照).

クラスタ作成後は「Cloud Service Mesh 有効なクラスタの作成」を通常通り最後まで行う 「Istio Ingress Gateway のインストール」へは進まず,以下の通りに進める

istioctl をダウンロードする

istioctl を使用して istiodistio-ingressgateway をクラスタにインストールする

⚠️ GKE Autopilot 環境では kube-system の変更が禁止されており,istio-cni ConfigMap の更新が行えない.そのため,istio-cni のインストールを禁止することでインストール失敗を回避している.

istioctl install -n istio-system -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
  name: istio-operator
  namespace: istio-system
spec:
  profile: default
  components:
    cni:
      enabled: false
    ingressGateways:
    - name: istio-ingressgateway
      enabled: true
EOF

結果

✔ Istio core installed ⛵️
✔ Istiod installed 🧠
✔ Ingress gateways installed 🛬
✔ Installation complete

Mutating Webhook Configuration によるインストール失敗の場合 新しいリビジョンやタグへの切り替えに失敗しているため,以下のコマンドで Admission Webhook オブジェクトを削除してから再度インストールする必要がある

kubectl delete mutatingwebhookconfiguration istio-revision-tag-default

これで Istio のインストールは完了です.

前述の通り特権コンテナを許可しているため,ご使用の際はセキュリティに十分注意して下さい.

参考資料

  1. Cloud Service Mesh 概要
  2. 【Istio⛵️】サービスメッシュの登場経緯とIstioサイドカーインジェクションの仕組み
  3. GKE でマネージド Cloud Service Mesh コントロール プレーンをプロビジョニングする
  4. Bookinfo サンプルのデプロイ
  5. Google Kubernetes Engine に Anthos Service Mesh をインストールする
  6. Cloud Service Mesh サービス ルーティング API の概要
  7. ゾーン ネットワーク エンドポイント グループの概要
  8. インターネット ネットワーク エンドポイント グループを使用した Cloud Service Mesh
  9. スタンドアロン NEG によるコンテナ ネイティブのロード バランシング
  10. Cloud Service Mesh サービス ルーティング API の概要
  11. GKE Autopilot のセキュリティ対策
  12. 【Istio⛵️】Istioによって抽象化されるEnvoyのHTTPSリクエスト処理の仕組み
  13. Istio | Request Routing

ブログ一覧へ戻る

お気軽にお問い合わせください

SREの設計・技術支援から、
SRE運用内で使用する
ツールの導入など、
SRE全般についてご支援しています。

資料請求・お問い合わせ