Anthos Service Mesh (ASM) は、Kubernetes向けサービスメッシュIstioのマネージド版です。マネージドコントロールプレーンを使ったマルチクラスタASMの構築手順を、ステップごとにわかりやすく解説します。

本記事では、マネージドコントロールプレーンを利用してマルチクラスタAnthos Service Mesh (ASM) を構築する手順を、ステップバイステップで紹介します。
サンプルコードはこちらで公開しています: https://github.com/caddac/anthos-examples/tree/main/asm
サービスメッシュとは、さまざまなコンピュートプラットフォーム(ここではクラスタ)上に構築される抽象化レイヤーで、サービス間通信、可観測性、セキュリティをシンプルにするものです。これらの責務をプラットフォーム側に寄せることで、アプリケーション自体をシンプルに保てます。本記事では、マネージドIstioであるAnthos Service Meshをデプロイします。IstioはKubernetes向けのサービスメッシュで、サービス間の可観測性とセキュリティを一貫した形で把握できる強力なツールです。Istioでは、すべてのサービス間通信をPodのサイドカーとして動作するプロキシ経由でルーティングすることで、これを実現します。
各サービスは、Istioが提供する一貫した透過的なパターンに沿って他サービスと通信できます。相手サービスへの到達方法、受信リクエストへのセキュリティ対策、サービス間トラフィックのメトリクス公開などを個別に意識する必要はなく、これらはすべてIstio側で処理されます。運用負荷が高まりがちなマルチクラスタ構成では、これらの機能の重要性はさらに増します。
一方で、サービスメッシュにはセットアップの複雑さ、リソースのオーバーヘッド、コストといったデメリットもあります。Istioは機能が豊富で、構成方法もistioctl、IstioOperator、helmなど複数用意されていますが、マネージドコントロールプレーンを使用するAnthos Service MeshはIstioOperator APIとhelmをサポートしていません。
本チュートリアルでは、2つのGKEクラスタを構築し、Istioのhello-worldアプリケーションをそれぞれにデプロイします。その後、片方のクラスタにのみIngressを1つインストールし、2つのGKEクラスタ上で動作する4つのhello-world Podへトラフィックがロードバランスされる様子を確認します。

Terraformをデプロイする
asm/infraディレクトリ内のvar_inputs.auto.tfvarsファイルの値を更新します。
plan・applyを実行します:
$ terraform init
$ terraform apply
注: applyに失敗した場合は、もう一度実行してみてください。依存関係のあるリソースを一度に大量に作成しようとすると、Terraformの処理が追いつかないことがあります。私の場合は全リソースが作成されるまで3回applyを実行する必要がありました。
ここでは多くの処理が行われているので、簡単に解説します。
新しいGCPプロジェクトをデプロイし、必要なAPIをいくつか有効化します [1]。なお、公式ドキュメントではstsとanthosのAPIが抜け落ちているようなので、忘れずに有効化してください。
さらに、VPC、セカンダリレンジを持つ2つのサブネット、すべてのリソース間で通信できるようにするファイアウォールルールもデプロイし、最後にプロジェクトでhub mesh機能を有効化します。
各ファイルがクラスタを1つずつデプロイします。違いはクラスタ名、リージョン、サブネット参照だけです。クラスタ設定で押さえておきたいポイントが2つあります。1つ目は、mesh_idラベルを設定し、このクラスタがどのメッシュに属するかをGCPに伝えていること。2つ目は、Workload Identityを有効にしていることです。これにより、JSONキーをダウンロードしたり作成したりすることなく、KubernetesサービスアカウントをGCPサービスアカウントとして扱えるようになります [2]。
クラスタはfleetに登録し、クラスタ名をmembership idとして利用します。
最後にマネージドコントロールプレーンをインストールします。今回はautomatic control-plane(つまり「マネージド」)を使用しますが、リビジョンはどう決まるのでしょうか? Namespaceのrevisionラベルを確認すれば、どのリビジョンのコントロールプレーンが使われているかがわかります [5]。たったこれだけです!
この時点で、同じfleet内に2つのクラスタが稼働し、いずれもマネージドコントロールプレーンによるASMがインストールされた状態になります。Istioコンポーネントのインストールに進めますが、クラスタ間のサービスディスカバリはまだ機能していません。
クラスタ間サービスディスカバリを構成する
fleet内の各クラスタについて、他のすべてのクラスタにシークレットをインストールする必要があります。幸いこれを行うCLIツール「asmcli」が用意されていますが、現時点ではmacOSで動作しないため、Cloud Shellで実行するのが一番簡単です。
GCPコンソールにアクセスし、Cloud Shellボタンをクリックして、プロジェクトのCloud Shellを開きます。

画面下部にコンソールが表示されたら、以下のコマンドを実行します:
$ curl https://storage.googleapis.com/csm-artifacts/asm/asmcli\_1.13 > asmcli
$ chmod +x asmcli
_$ ./asmcli create-mesh ${GOOGLE_CLOUD_PROJECT} _
_${GOOGLE_CLOUD_PROJECT}/us-west1/${GOOGLE_CLOUD_PROJECT}-cluster1 _
${GOOGLE_CLOUD_PROJECT}/us-east1/${GOOGLE_CLOUD_PROJECT}-cluster2

補足: プライベートクラスタを使用している場合は、クラスタ間サービスディスカバリを有効にするために追加の手順が必要です [6][7]。
アプリとIstioコンポーネントをデプロイする
asm/manifestsディレクトリから、メッシュの動作確認用アプリをインストールできます。クラスタ1には、helloworldアプリとIngress用のIstioコンポーネントをインストールします。
まず、各クラスタのコンテキストを取得します:
export PROJECT_ID=<gcp_project_id>
gcloud container clusters get-credentials ${PROJECT_ID}-cluster1 --region us-west1 --project ${PROJECT_ID}
gcloud container clusters get-credentials ${PROJECT_ID}-cluster2 --region us-east1 --project ${PROJECT_ID}
クラスタ1には次のコマンドでインストールします:
kubectl apply -k manifests/ --context=gke_${PROJECT_ID}_us-west1_${PROJECT_ID}-cluster1
クラスタ2には次のコマンドでインストールします:
kubectl apply -k manifests/app/ --context=gke_${PROJECT_ID}_us-east1_${PROJECT_ID}-cluster2

動作を確認する
数分待てばすべてが立ち上がっているはずなので、結果を確認していきましょう。
両クラスタでhelloworldのPodが稼働していることを確認します:
$ export PROJECT_ID=<gcp_project_id>
$ kubectl get pods -n helloworld
--context=gke_${PROJECT_ID}_us-west1_${PROJECT_ID}-cluster1
$ kubectl get pods -n helloworld
--context=gke_${PROJECT_ID}_us-east1_${PROJECT_ID}-cluster2

クラスタ1でingress-gatewayのDeploymentが稼働していることを確認します。
$ kubectl get deploy -n asm-gateways --context=gke_${PROJECT_ID}_us-west1_${PROJECT_ID}-cluster1

クラスタ1のingress-gatewayサービスに外部IPが割り当てられていることを確認します。
$ kubectl get svc -n asm-gateways --context=gke_${PROJECT_ID}_us-west1_${PROJECT_ID}-cluster1

最後に、パブリックエンドポイントに何度かリクエストを送り、クラスタ間のロードバランシングが機能していることを確認します。リクエストごとに当たるPodが変わるため、バージョンとPod IDが切り替わる様子が確認できます。4種類のPod IDと2種類のバージョンが返ってくるはずです。

$ curl /hello

カスタマイズとログの確認
Envoyのデバッグログを有効にする
これはASMの設定をデプロイした時点ですでに済ませています。asm/manifests/gateways/asm-config.yamlファイルをご覧ください。デプロイしたConfigMapで、Envoyプロキシがアクセスログをstdoutに出力するよう設定しています。同様の手順で有効化できる他のオプションもあります [3]。
コントロールプレーンのログ
マネージドコントロールプレーンを使用していても、コントロールプレーンのログを確認できます。Logs Explorerで、リソース「Istio Control Plane」の配下に表示されます。
参考資料
- https://cloud.google.com/service-mesh/docs/managed/auto-control-plane-with-fleet#before_you_begin
- https://cloud.google.com/kubernetes-engine/docs/how-to/workload-identity
- https://cloud.google.com/service-mesh/docs/managed/enable-managed-anthos-service-mesh-optional-features
- https://cloud.google.com/service-mesh/docs/managed/auto-control-plane-with-fleet
- https://cloud.google.com/service-mesh/docs/managed/select-a-release-channel#how_to_select_a_release_channel
- https://cloud.google.com/service-mesh/docs/unified-install/gke-install-multi-cluster#private-clusters-endpoint
- https://cloud.google.com/service-mesh/docs/unified-install/gke-install-multi-cluster#private-clusters-authorized-network