Cloud Run でマイクロサービスを作る 5 つのポイントをまとめてご紹介!

Takayuki Yorikane
google-cloud-jp
Published in
13 min readOct 4, 2021

--

はじめに

早速ですが、皆さんはマイクロサービスを構築するとしたら、どのような構成を考えますか?

多くの企業で、GKE を使ったマイクロサービス アーキテクチャが採用されています。選定理由として、Kubernetes が持つ機能や大きめなリソースが必要であったり、社内インフラチームによる Kubernetes のサポートがあるといった理由などがあります。一方、定期アップグレードなどの観点から、Kubernetes の運用は少し大変…と感じる方もいるかと思います。

GKE Autopilot の利用という考えもありますが、サーバーレスでコンテナを動かせる Cloud Run を使って、インフラ管理不要でマイクロサービスを構築が出来ると嬉しくないですか?
実際、そういった構成を採用されている企業も見かけます。
この記事では、設計や実装時に考えるであろう、以下の 5 つのポイントにフォーカスしてみたいと思います!

  1. Cloud Run の制約を理解する
  2. 最小権限の原則を適用する
  3. ロードバランサでトラフィックを管理する
  4. ネットワークの制約をいれる
  5. タスクを分離する

1. Cloud Run の制約を理解する

まずは、Cloud Run の割り当てと上限を知っておくべきでしょう。

Cloud Run サービス(以下総称して「サービス」と表記します)は、リージョン毎に作られ、複数のリビジョンを持ち、リビジョン毎にコンテナ インスタンスが紐付いています。
各階層における制約がありますので、詳細はドキュメントを参照してください。特に考慮すべきは、サービスやコンテナ インスタンス毎の上限と、受信するリクエスト毎の上限です。

サービスには複数のリビジョンが紐づき、最小単位はコンテナ インスタンス

2021 年 9 月現在、サービスあたり 1,000 コンテナ インスタンスまでスケールすることができ、コンテナ インスタンスに割り当てられる最大リソースは 4 vCPU、8 GB メモリ、1 コンテナ インスンタンスが受信できる同時リクエスト数は 1,000、リクエスト毎の最大タイムアウトは 60 分という値となっています。

サービスやコンテナ インスタンス、リクエストごとに制約がある

マイクロサービスの分離レベルを細かくして、サービスを別にすると、リソースやスケール上限に余裕が出てくるでしょう。一方、1 リージョンにおけるサービスの最大数は 1,000 なので、大規模なシステムにおいては分離しすぎる際に注意が必要かもしれません。

1 つのマイクロサービスにおいても、使用リソースの大小、レスポンスタイムの速度など、ユースケースが違うものが混在する場合、サービスを分離しておくことで、タイムアウト指定や同時リクエスト数など最適化出来ます。

API 利用と、Batch 利用でサービスを分離した場合の例

動かすワークロードと制約を比較して設計することで、機能とリソースを追従させていくことが比較的容易になるはずです。

2. 最小権限の原則を適用する

マイクロサービスを構成する場合、最小権限の原則に従い、各サービスで実行できる権限は絞る必要があります。

Google Cloud のサービスには、ユーザーに代わって処理を行うためのサービス アカウントを指定できることが多く、Cloud Run では、サービス アカウントを各サービス単位で指定することが出来ます。サービス アカウントを指定しない場合は、Compute Engine default service account が利用されるため、強い権限をサービスが持つことになるのですが、個別にサービス アカウントを指定すれば、サービスが必要とする権限だけを指定サービス アカウントに持たせれば良い、ということになります。

サービス アカウントの権限を制限する

フロントエンドのようなサービスであれば誰からもアクセスを受け付けて良いが、バックエンドとなる API サービスなどは、呼び出し元の特定サービスに制限したい、という場面もあるはずです。

サービス間通信において、特定サービスからのアクセスを許可するよう制限したい場合、まず、リクエストを受信するサービスで認証を必須にします。そして、呼び出し元のサービスに紐付いているサービス アカウントに対し、 roles/run.invoker ロールを付与して、受信側サービスのメンバーにします。

gcloud run services add-iam-policy-binding RECEIVING_SERVICE \
--member='serviceAccount:CALLING_SERVICE_IDENTITY' \
--role='roles/run.invoker'

ロールを付与したら、ID トークンを取得して、ヘッダに含めれば認証必須のサービスに到達することが出来ます。

ロールを付与した呼び出し元のサービス アカウントだけアクセス可能

機能が増えて新しい権限が必要になった場合も、サービス単位で権限を調整できるため、容易に最小権限を維持することが出来るのが便利ですね。

3. ロードバランサでトラフィックを管理する

Cloud Run はコンテナをデプロイするだけで、外部からアクセス可能な URL が発行されます。単一アプリをデプロイする上で非常に便利なのですが、マイクロサービスを本番で運用することを考えると、Google Cloud Load Balancing(GCLB)を利用してトラフィックを管理したい、ということもあると思います。

そういった運用を考慮して、Serverless NEG を利用してCloud Run と GCLB を連携させておくと良いでしょう。まず、NEG について説明すると、これは Network Endpoint Group の略であり、GCLB のバックエンドとなるサービスやエンドポイントのグループを表すものと考えてください。現在、NEG は 5 種類存在しています。

この Serverless NEG が、App Engine や Cloud Functions、Cloud Run といった Serverless のプロダクト群で利用する NEG になります。

1 つの GCLB バックエンド サービスには、リージョン毎に 1 つの Serverless NEG が設定でき、1 つの Serverless NEG につき、1 つの Cloud Run エンドポイントが紐づきます。また、ホストやパスベースで、異なるバックエンド サービスへルーティング可能です。これらの関係性については、以下のブログでより理解が深まると思います。

また、GCLB を連携させることにより、Cloud Armor を利用した WAF の導入や DDoS 対策などもバックエンド サービス毎に導入できます。最近では、Rate Limit の機能(Preview)もリリースされており、クライアント毎のトラフィック制御も加えることが出来たりもします。

他にも、Identity-Aware Proxy(IAP)を有効化して、特定の認証ユーザだけをバックエンド サービスにアクセス可能とすることが出来ます。つまり、管理ツールのような特定のアクセスに制限したいマイクロサービスでも、Cloud Run をバックエンドとして使えるということです。

Cloud Armor や IAP はバックエンド サービスに指定

マイクロサービス毎に、ホストや、パスの prefix を分けて、GCLB のレイヤでトラフィックを分離することで、開発、モニタリング、セキュリティなど様々な分野において設計範囲が広がります!

4. ネットワークの制約をいれる

GCLB と統合したのは良いが、Cloud Run 自体でも URL 発行するのでは?と感じる方もいると思います。その懸念を解消するためのネットワークの制御も、Cloud Run の機能として提供されています!

GCLB と統合したのであれば、Cloud Run へ直接アクセスするのは禁止にし、LB 経由のトラフィックだけを許可するべきです。Cloud Run では、内向きのネットワークの許可設定が、以下 3 つから選べます。

  • すべてのトラフィック
    インターネットからサービスにアクセス可能
  • 内部トラフィックのみ
    同プロジェクト、VPC Service Controls の境界内、Pub/Sub、Eventarc から発生したリクエストのみアクセス可能
  • 内部トラフィックと Cloud Load Balancing
    内部トラフィック + GCLB 経由のリクエストがアクセス可能

この「内部トラフィックと Cloud Load Balancing」を選択すれば、外部から Cloud Run の URL に対するアクセスは許可されません。そのため、前述の GCLB に設定した機能を必ず通って、外部からのアクセスが流れてくることが保証されます!

内部トラフィックと、Cloud Load Balancing からのトラフィックのみを許可

より細かく内部トラフィックの制約を入れたい場合は、VPC Service Control(VPC SC)を使って Cloud Run が連携する境界を詳細に定義することも出来ます。

VPC SC の適用には、組織閲覧者と、Access Context Manager 編集者のロールが必要

Cloud Run はゼロトラストとも相性は良いですし、ここで紹介したように内部トラフィックにアクセスを制限したり、Serverless VPC Access を使って、VPC 内のデータベースなどにアクセスすることも可能です。アクセス制御を Cloud Run が提供する機能だけで簡単に導入できるのは非常に便利ですね。

5. タスクを分離する

サービスのリクエスト方法は、呼び出し元サービスからのダイレクトな同期 or 非同期呼び出しだけでなく、Cloud SchedulerPub/SubCloud Tasks を介して呼び出す方法、または、Eventarc を利用してイベント駆動で実行する方法など様々です。

また、Workflows を利用して複数の処理を構成することで、マイクロサービス間のトランザクションを実現することも出来ます。この内容については、以下のブログが分かりやすいので、ぜひ参考にしてみてください。

Cloud Run の機能と、これらを組み合わせることで、マイクロサービス間の連携に幅が広がってきます。具体的に、EC のアーキテクチャを例にユースケースを考えてみましょう。

ざっくり大まかに考えたアーキテクチャです

(全体表示だと小さすぎたので、拡大しつつ説明します。。)

在庫情報や商品情報が、倉庫や外部システムから Google Cloud Storage(GCS)を経由して取り込まれるとしたら、Eventarc を使って、ファイルなどのオブジェクトが GCS に作成されたのをトリガーに、各マイクロサービスで取り込み処理を走らせることが出来ます(黄色の線)。商品サービスが管理している情報を検索インデックスに取り込むようなサービス間の連携の場合も同様にトリガーを走らせ、差分で検索データを取り込ませることが出来ます(緑の線)。

GCS → Eventarc → Cloud Run → DB

ここで重要なのは、各マイクロサービスの責任範囲が明確に分離されていることです。データ送信側は正常にデータを配置するまでが責任範囲、データ取り込み側は受信イベントデータをきちんと処理することが責任範囲です。この中継を行うために Eventarc を利用する形になります。

また、図の下の方にある注文サービスでは、注文リクエスト情報を Pub/Sub に入れておき、別の Cloud Run サービスが Pull 型でデータを取り出して、さらに裏側の発注システムにリクエストしています(赤い線)。

これまでの Cloud Run は、サービスがリクエストやイベントを処理している間のみ CPU が割り当てられる仕組みでした。そのため、バックグラウンドの処理を常時動かしておきたいような場合に利用が難しかったのですが、 最近、Cloud Run に Always-on CPU allocation の機能がリリースされ、これにより、CPU を常時割り当てて、Pull し続けるようなアプリも実行することが出来るようになりました。詳しくは以下のブログが参考になるかと思います。

マイクロサービスでは、DB ホストやアプリケーションそのものだけでなく、どれだけ明確に責任範囲を分離できるかが開発を円滑に回すポイントになってきます。Cloud Run が連携できるこういった機能を活用することで実現しやすくなるはずです。

さいごに

Cloud Run はサーバーレスでコンテナを動かす PaaS として非常に便利なサービスです。現在提供している機能でカバー出来るのであれば、マイクロサービスの運用も問題ありません。むしろ、管理が必要なレイヤが狭まるので、インフラ管理に困っている組織には特におすすめです。

今回 5 つのポイントに絞ってみましたが、○○も考慮しないといけない!こうした方がより良い設計になるでしょ!と言った意見も当然あるかと思います。ぜひ色々な考えを聞いてみたいので、Twitter にでも投稿してもらえるとありがたいです!

--

--

Takayuki Yorikane
google-cloud-jp

Application Modernization Specialist at @GoogleCloud. Opinions are my own, NOT the views of my employer. All posts here are my personal opinion.