Cloud Run のサービスメッシュを試した
Cloud Run のサービスメッシュを試した
以前から GKE では Cloud Service Mesh を使ってサービスメッシュを利用することができましたが、Cloud Run でもサービスメッシュを利用できるようになりました(作成時点の2024-09-02ではプレビュー段階)。
この記事ではサービスメッシュならではの機能をサンプルアプリを使って確認します。
検証シナリオ
検証環境の構成
サンプルアプリとして Istio のドキュメントに掲載されている bookinfo
(本の情報やレビューが見られる Web アプリで、マイクロサービスで実装されている)のコンテナイメージを利用します。
検証する機能
下記の4点について確認を行います。
- サービス間の認証、認可を自動的に行う
- 従来の Cloud Run では ID トークンを明示的にヘッダに付与してリクエストを送信する必要があり、アプリの実装で意識する必要がありました。サービスメッシュを利用することで、アプリ側では実装しなくても自動的に付与されるようになります。
- 独自に設定したドメイン名でのサービス ディスカバリ
- 宛先として Cloud Run が自動的に付与する
https://servicename-abcdef1234-ab.a.run.app
またはhttps://servicename-123456789012.region.run.app
形式の URL ではなく、任意のドメイン名を付与することが可能です。
- 宛先として Cloud Run が自動的に付与する
- オブザーバビリティ
- Cloud Trace を使った分散トレーシングを利用することができます。マイクロサービスの呼び出しは 2 の独自ドメイン名で表示されます。
- 高度なトラフィック管理、フォールト インジェクション
- 条件によるトラフィックの振り分けやエラーの注入を行うことが可能になりました。従来からある Cloud Run のリビジョンのトラフィック振り分け機能を併用することも可能です。
検証環境の構築
Cloud SDK(gcloud
コマンド) は 488.0.0(2024-08-13)以降が必要です。
サービスメッシュの作成は一度ですが、Cloud Run サービスの作業はクライアント側か宛先側かによって必要な作業が異なります。クライアント側と宛先側の両方の役割を持つサービス(この例では reviews
サービス)では両方の作業を行います。
メッシュの作成時 | クライアント側の Cloud Run デプロイ | 宛先側の Cloud Run のデプロイ | |
---|---|---|---|
サービスメッシュの作成 | ○ | - | - |
DNS の設定 | ○ | - | ※1 |
Cloud Run のデプロイ | - |
--network , --subnet , --mesh オプションが必要 |
特別なオプション不要 |
ネットワーク関連の設定 | - | - | サーバーレス NEG の作成、INTERNAL_SELF_MANAGED のバックエンドサービスの作成と NEG との紐付け、HTTPRoute の作成 |
必要な IAM ロール | - |
Cloud Service Mesh Client , Cloud Run Invoker
|
- |
※1: VPC から Cloud Run への接続を Private Service Connect にて行う場合は必要。本記事では Google Private Access を用いる構成のため行わない
API の有効化
必要な API 群を有効にします。具体的な API 名はドキュメントを参照してください。
サービスメッシュの作成
YAML ファイルを作成し、それをインポートしてサービスメッシュを作成します。
name: bookinfo
gcloud network-services meshes import bookinfo \
--source=mesh.yaml \
--location=global
DNS の設定
サービスディスカバリに利用するドメイン名を Cloud DNS のプライベートゾーンとして登録します。今回は bookinfo.internal
を使います。
作成したゾーンにワイルドカードの A レコードを作成します。宛先の IP アドレスが RFC 1918(いわゆるプライベート IP)の範囲である場合、Cloud Run サービスのサイドカーがそのリクエストをメッシュ内の適切な宛先へ転送します。したがって複数の宛先サービスがメッシュにある場合でも、サービスごとに個別の IP アドレスを割り当てる必要はありません。
gcloud dns managed-zones create bookinfo \
--description="Domain for bookinfo.internal service mesh routes" \
--dns-name=bookinfo.internal. --networks=meshvpc \
--visibility=private
gcloud dns record-sets create "*.bookinfo.internal." \
--type=A --zone="bookinfo" --rrdatas=10.0.0.1 --ttl=3600
宛先となる Cloud Run サービスのデプロイ
Cloud Run サービスのデプロイ
サービスメッシュ宛にリクエストを送信しない Cloud Run サービスは従来と同じようにデプロイすることができます。Bookinfo では、ratings
と details
サービスがあてはまります。
gcloud run deploy ratings --region=us-central1 \
--image=docker.io/istio/examples-bookinfo-ratings-v1:1.19.1
(details
も同様なので省略)
次にサーバーレス NEG を作り、サービスメッシュに登録します。
gcloud compute network-endpoint-groups create destination-neg-ratings \
--region=us-central1 --network-endpoint-type=serverless \
--cloud-run-service=ratings
gcloud compute backend-services create ratings-us-central1 --global \
--load-balancing-scheme=INTERNAL_SELF_MANAGED
gcloud compute backend-services add-backend ratings-us-central1 --global \
--network-endpoint-group=destination-neg-ratings \
--network-endpoint-group-region=us-central1
HTTPRoute リソースの YAML ファイルを作り、インポートします。
name: "ratings-route"
hostnames:
- "ratings.bookinfo.internal"
meshes:
- "projects/PROJECT_ID/locations/global/meshes/bookinfo"
rules:
- action:
destinations:
- serviceName: "projects/PROJECT_ID/locations/global/backendServices/ratings-us-central1"
gcloud network-services http-routes import ratings-route \
--source=http_route_ratings.yaml --location=global
クライアント側の Cloud Run サービスのデプロイ
Cloud Run サービスのデプロイ
クライアント側のCloud Runサービスはいくつかのオプションを付けて作成する必要があります。
gcloud beta run deploy productpage \
--region=us-central1 \
--image=docker.io/istio/examples-bookinfo-productpage-v1:1.19.1 \
--network=meshvpc \
--subnet=us-c1 \
--mesh="projects/PROJECT_ID/locations/global/meshes/bookinfo" \
--port 9080 \
--set-env-vars=DETAILS_HOSTNAME=details.bookinfo.internal,DETAILS_SERVICE_PORT=80,RATINGS_HOSTNAME=ratings.bookinfo.internal,RATINGS_SERVICE_PORT=80,REVIEWS_HOSTNAME=reviews.bookinfo.internal,REVIEWS_SERVICE_PORT=80 \
--service-account=cloudrun-in-mesh@PROJECT_ID.iam.gserviceaccount.com
接続するVPCネットワーク(--network
)とサブネット(--subnet
)、サービスメッシュのID(--mesh
)を指定します。
このアプリはバックエンドのサービスのホスト名とポートを環境変数で指定できるようになっているので、それぞれ指定します。ホスト名は HTTPRoute
の YAML ファイル内で指定したもの、ポートは 80
とします。
IAM ロールの付与
クライアント側の Cloud Run サービスが利用するサービスアカウントに下記の IAM ロールを付与します。
- 宛先の Cloud Run サービスに対して
roles/run.invoker
ロール -
roles/trafficdirector.client
ロール
動作確認
productpage
のサービスのURLを開くと、サンプルアプリの画面が出ます。
バックエンドのサービスへ接続する URL として、最初に設定した *.bookinfo.internal
の URL が指定されていることがわかります。
ページの下にある Normal user
か Test user
リンクから本の情報が表示されるページを開きます。
ここまでの検証では特にアプリの実装に手は入れていませんが、動作していることがわかります。検証項目1: サービス間の認証、認可を自動的に行う、と検証項目2の独自に設定したドメイン名でのサービスディスカバリ を確認することができました。
右下に Reviews served by: null
と出ているのは、アプリが環境変数 HOSTNAME
を必要とする仕様ですが Cloud Run のデフォルトでは設定されないからです。
次に Cloud Trace の画面を開きます。
先ほどアクセスしたときのトレースが記録されており、フロントの productpage
アプリからバックエンドのマイクロサービスの呼び出しがされている様子がわかります。このときの宛先は *.bookinfo.internal
になっていることも確認できます。
設定を変えてみる
まずはサービスメッシュではなく Cloud Run の既存の機能で reviews
アプリへのトラフィックを振り分けます。
reviews
アプリはバージョン2が黒い★、バージョン3が赤い★を表示する仕様です。
何度かリロードすると意図したとおりトラフィックが振り分けられていることを確認できました。
フォールトインジェクション
次はマイクロサービスの呼び出し部分で意図的にエラーが発生するようにします。HTTPRoute
の YAML ファイルに faultInjectionPolicy:
以下を追加します。この例では、1.5 秒の遅延とステータスコード 500
のエラーレスポンスが必ず返るようにしています。
name: "ratings-route"
hostnames:
- "ratings.bookinfo.internal"
meshes:
- "projects/PROJECT_ID/locations/global/meshes/bookinfo"
rules:
- action:
destinations:
- serviceName: "projects/PROJECT_ID/locations/global/backendServices/ratings-us-central1"
+ faultInjectionPolicy:
+ delay:
+ fixedDelay: "1.5s"
+ percentage: 100
+ abort:
+ httpStatus: 500
+ percentage: 100
最初に HTTPRoute を作成したときと同じように YAML ファイルをインポートします。
gcloud network-services http-routes import ratings-route \
--source=http_route_ratings.yaml \
--location=global
その他、設定可能な項目はドキュメント を参照してください。
YAML ファイルに記載する詳細な項目のスキーマはAPI 定義ファイル の schemas
に載っています。
動作確認
productpage
をリロードするとレビュー欄の点数が表示されておらず、ratings
サービスが利用不可能になったことがわかります。
Cloud Trace を確認すると、レスポンスまで 1.5 秒かかっていること、ステータスコードが 500
になっていること、ratings
サービスにはトラフィックは行っていないことがわかります。
まとめ
Cloud Run と Cloud Service Mesh を組み合わせることで、マイクロサービスの実装や運用がより簡単になります。ぜひ皆様のアプリでも検証してみてください。
Discussion
めちゃくちゃ便利そう!
複数の Google Cloud プロジェクトをまたいだ Mesh も構築できるのでしょうか?
宛先の Cloud Run サービスを外部のプロジェクトに構築してトラフィックを流せることを確認しました。
宛先のサービスを操作するユーザからメッシュが存在するプロジェクトに対して roles/compute.networkAdmin ロールが必要です。
参考ページ