hiroportation

ITの話だったり、音楽の話、便利なガジェットの話題などを発信しています

GCPマイクロサービス・ソリューションアーキテクチャ・ディクショナリー


0. はじめに

GCPベースでマイクロサービス・ソリューションアーキテクトに必要なナレッジをまとめてみました。
本誌は随時更新し拡充・最新化していきたいと思います。

あくまで自身の考えをまとめたものになり、間違えや一部主観も含まれる可能性があるためご了承ください。


1. GCPベースでのマイクロサービス全体設計


マイクロサービス基盤においてGCPを選定する理由・観点
  • 社内、事業部等において、GCPの利用実績やナレッジが豊富であるか?
  • 足りない機能はAWS等、他クラウドを利用する事が可能である(マルチクラウド)?
  • GCPの特定サービスについて利用要求があるか?

※経験上、重要度の高い観点をピックアップしています


マイクロサービスアーキテクチャとはどういうものか

マイクロサービスアーキテクチャは膨大なコンポーネントを整理するために、マイクロサービス毎に「役割」を定義することがとても大切なこととなる。

  • BFFはUX/UIに依存したバックエンド処理を行うため再利用しない
  • ビジネスロジックについて処理を集約するために再利用を前提とした作りとし、ロジックの重複を防ぐことで生産効率化を目指す
  • 外部システムとの連携の際には、専用の連携マイクロサービスを設けることにより、処理や修正対応の集約を実現することができます

GCPではこれら役割を持つマイクロサービスをGKEやCloudRunなどのコンテナエンジンにて実装します。

これにより、コンテナ内の各ロジックを重複なく集約し、無駄のないシンプルなマイクロサービス基盤を実現する。


マイクロサービスの設計観点
論点 説明
サービス粒度・分割単位 業務視点、システム視点、双方での考慮が必要
・単一責任を意識し、必ず複数組織が一つのサービスの意思決定をしないようにする
トランザクション境界、障害時の影響、技術特異性を考慮
俊敏なリリース 後方互換性バージョンアップであり、複数バージョン共存可能なAPIルーティングにより、マイクロサービス毎に独立的なリリースを実現
データ分離 DBなどで扱うデータは整合性のため、単一サービスからの利用とし、複数組織・複数サービスでの利用しないこと
疎結合 マイクロサービスは独立性を持つことで、他プロダクトに依存せず迅速にリリースを実行できる


マイクロサービス設計で意識すること
  • マイクロサービスは拡張に伴いコンポーネントや通信箇所が増え複雑になりやすいため、シンプルな設計を常に心がけること
  • 目先の設計だけで無く、将来を見据えた設計を行うこと
  • 業務ドメインを正確に把握して、ドメインにマッチしたインフラデプロイを心がけること(例えば高セキュア用の基盤など)


GCPにおけるマイクロサービス実装パターンについて

GCPにおいてマイクロサービスを実装するにはいくつかパターンがあり、主に規模や体制面を考慮して選定する。

サービス構成パターン メリデメ
CloudRunを中心に、VPCにて中小規模なコンテナ通信を管理する 主にフルマネージドサービスを利用するため、インフラ管理・運用の必要がないが、スケールに伴い利用サービス数が増え管理が増加するため中小規模での利用が前提となる
GKEを中心に、ServiceMeshを利用した大規模なコンテナ通信を管理する メッシュによる細かいNW制御が可能になるが、GKEクラスタの運用が必要となる
CloudRunとCloud Service Meshを中心とした大規模なコンテナ通信を管理する 上記二つのデメリットを解消できるためほぼ全ての要件でベスプラとなり得るが、メッシュが2024/9現在ベータ版であり、本格利用は少し先


マイクロサービスにおけるシングルテナントとマルチテナント

シングルテナントかマルチテナントかで、マイクロサービス開発のアプローチや難易度が大きく異なってきます。

特に複数ベンダーが開発を行うマルチテナント下では共有ライブラリやマイクロサービスによる共通化は通常の開発と違い、相応の性能試験や利用マニュアルの展開などがあるため、共通化専用チームは必須となります。


どこまで共通化・標準化するのか?

マイクロサービスでは様々な様々なものを標準化

通化項目 通化内容
マイクロサービス 機能の再利用
共有ライブラリ アーティファクト(機能)の再利用
開発標準 コーディングルール(コード規約)


GCPにおけるポリシーコントロール

GCPにおいてポリシー管理方法は大きく2パターンあると考えます。

  • GKE Policy Controllerで管理
  • GCP プロジェクトで管理

マイクロサービスにおいてこれまではGKEをメインで使う事が多かったためPolicy Controller が有益と考えてましたが、 Cloud Service Meshによるメッシュの低レイヤ化により、ポリシーはプロジェクトにて容易に管理可能となる想定。


GCPにおける標準ライブラリの実現について

GCP基盤にておいて標準ライブラリ実装を実現させる場合、Artifact Registryを利用します。 Githubを使っている場合はGithub Packagesを利用しますが、対応フレームワークがネックとなることが多い印象です。

Artifact Registryの場合、GoモジュールやPythonパッケージも保存可能なため、様々な要件に対応する必要があるマイクロサービスと相性が良いように思えます。


2. UX/UI (Webアプリ、モバイルアプリ)

UX/UIには大きく分けてWebアプリとモバイルアプリ(ネイティブアプリ)の2種類が存在する。


2.1. Webアプリ


UX/UIのビジネスロジックをバックエンドに寄せる必要性

一般的にフロントエンドはビジネスロジックをバックエンドに寄せることにより、描画処理に専念し、Light Weightなものとする。 特にSPAを利用する場合、効果を最大限にするためにページ遷移のたびに処理が重くならないようにしたい。


SPAか?SSRか?

UXUIのレンダリングに関しては主にSPAとSSRのどちらかで議論になる。 大規模・高負荷になると、SSRではバックエンドコストが課題なってしまうため、大抵の場合SPAを選定する方が良い印象。 SPAの場合初回表示速度がネックとなるため、SEO対策を実施する事。 初回アクセス時の高速なレスポンスなどSSRがどうしても必要な要件の場合のみ実装する。


マイクロフロントエンドの採用有無

マイクロフロントエンドは1画面にさまざまな情報を持たせる際に適しています。ただし全体的な画面フレームを複数組織で合わせる必要があるため、コミュケーションに注意が必要です。
UXUI全体デザイン設計を行うチームがいれば問題ありませんが、チームを設けることが難しい場合、一般的なSPAを採用します。


SPA(CSR)とSSR等の複数レンダリング対応はなるべく避ける

理想としてはSPAとSSRレンダリングを使い分けられると良いですが、インフラ運用コストが倍以上となるため、なるべく避ける事


CMSを活用して資材を資材の共通化

フロントエンド開発の効率化のため、フロントエンド資材の共通化にはCMSを利用します。 有名どころではAEMでヘッドレスCMSを利用する事によりフロントエンド資材の共通化、再利用により、マイクロサービス全体の開発効率をなるべく効率化される事


2.2. モバイルアプリ


モバイルアプリ開発にて考慮するべき点

モバイルアプリ開発において最初に考慮する点についてまとめる

項目 説明
マルチプラットフォーム モバイルアプリは特にiOSAndroidなどの複数プラットフォームで展開することが一般的なため、コスト低減のためマルチプラットフォームに対応した言語を選定します。2024年時点ではFlutter(Dart言語)がメジャーです。
mBaaS モバイルアプリでは専用のバックエンドサービスが存在しており、それらを使うのが一般的です。特にこだわりがなければシェアの大きいFirebaseを利用することでバックエンド開発コストを大きく削減できます。
iOS開発 モバイルアプリの場合、iOS向けアプリ開発MacOSが必要になるため注意が必要です


マイクロサービスにおける mBaaS の立ち位置

モバイルアプリはできるだけmBaaSを利用してバックエンドをデプロイしつつ、必要に応じてマイクロサービスを再利用したりすることにより、コスト最適化を実現します。


そもそもネイティブアプリ開発コスト削減のためのPWA機能

ネイティブアプリの開発にはWebアプリとは別の専門知識や専用の環境が必要になります。 そのためPWAというWebアプリ機能を使用して、プッシュ通知やオフライン利用といったネイティブアプリのようなことを低コストで実現できます。


3. API


BFFの設計
  • Backend for Frontend の通りフロントエンド設計・開発のために設けます
  • 1フロントにつき1BFFとすることでプロダクト毎の固有ロジックの変更を他プロダクトに依存せず可能


共通なビジネスロジック(マイクロサービス)
  • 通常プロダクトから共通化できそうなロジックを検討して切り出し、共通利用するマイクロサービスとしてデプロイする
  • 共通に利用するマイクロサービスはBFFなどと比べ利用率が高くなると思われるためパフォーマンスや公開方法については特に注意が必要
  • APIの公開はAPI-Gateway(又はApigee)や、GithubPagesとSwaggerを組み合わせて行います


API Gateway
  • GCPにおいては Apigee と API Gateway が主な選択肢となります
  • いずれもAPIアクセスにより料金が発生するため、たとえば認証が必要のないプロダクトに関してはXLB(ExternalLB)から直接プロダクトのバックエンドにアクセスさせるパターンも有りです(流量や不正アクセスへの対応は必要)
  • API Gateway はバックエンドへの入り口となるため、認可制御にも利用します
  • バックエンドへの通信が集中するところであるため、流量制限やリトライ、タイムアウトの役割として利用するのに適しています


4. 認証/認可


マイクロサービスにおける認証方式

複数のサービスを持つマイクロサービスではOAuthやOIDCを組み合わせて、SSOを実現することが一般的。 また、サービスの機密度などによりワンタイムパスワードやMFAなどを追加して適切なセキュリティを設定します。


認証で意識するべきこと
  • フロント(ブラウザ等)に見せて良い情報と見せてはいけない情報を明確に区別すること
  • フロントに高機密な情報(顧客情報など)を持ってくる際には必ずトークン化させたり、シークレット化させたりすること
  • フロントに
  • 認証と認可の役割のコンポーネント


アクセストークンとリフレッシュトークンはフロントに渡す頻度が違う

OIDC標準に従うとアクセストークンとリフレッシュトークンは共にサービスを利用するために使う大切な情報ですが有効期限が大きく違います。アクセストークンは大抵1時間いないですが、リフレッシュトークンは90日以内が一般的です。 この場合、アクセストークンは漏れてもすぐに使えなくなりますが、リフレッシュトークンは長い間不正利用されてしまいます。

なのでリフレッシュトークンはなるべくフロントに渡さないようにする必要があります。


認証認可

マイクロサービスにおける認証設計で大事なことは認証と認可の役割を明確に分けて考えることです。
認証はGoogle Cloud Identity Platform(IdP)を利用して正常に認証完了したアクセスに対してJWTを発行し、JWTを持ち回ってAPI-Gatewayにてアクセスコントロールを行うことでSSOを実現させます。
この時、Cloud IdPは「認証」の役割、API-Gatewayは「認可」の役割を持つことで認証認可の役割を明確にする。


JWTに持たせる情報

Cookieとしてフロントに返却するJWTは認証に使用するため、JWTに持たせる情報を整理することは情報漏洩や不正アクセスにもつながることもあるためとても大事なことです。 例としては以下となります。

JWT設定の注意点 対応策
ユーザを直接特定できる情報は不正利用される可能性があるため入れない UUID+Timestamp等にして時間毎に変化するものとする
JWTの有効期限は必要最小限とする 通常はアクセストークン、IDトークンは30分から1時間、リフレッシュトークンは半年などだが、金融などセキュアなサービスにおいてはより短い時間設定を検討する
OIDC標準に基づいた対策を実施する stateやnonceによる脆弱性対策は必須とし、必要に応じてホワイトリストなども検討する


5. インフラアーキ


GCP マイクロサービス基盤において主に使われるサービス群
主なサービス名 説明
Cloud Armor DDoS対策、セキュリティルール設定に利用
Cloud NAT Podなどの内部からインターネットへ通信するために利用
Cloud LoadBalancer 一般的にはAPI-Gatewayなどの外部からの通信を負荷分散するExternalLBと、ExternalLBから各マイクロサービスへ通信を負荷分散するInternalLBとして利用する場合が多い
Cloud DNS 一般的にインターネットからアクセスできる外部DNSと内部アクセスの内部DNSの2種類をデプロイします
Cloud Identity Platform 認証アカウントの管理に利用
GKE & ASM (次期Cloud Service Mesh) 大規模マイクロサービス基盤のデプロイにはGKE&ASMを利用します
Apigee or API Gateway 大規模であればApigeeを選定それ以外であればAPI Gatewayを選定


VPCの設定
  • DR を想定する場合はリージョン毎のVPCを用意
  • 大規模になれば複数プロジェクトも考えられるためその場合は適宜Shared VPCにてネットワークを結合(集約)する


サブネットの設定
  • 一般的にはマイクロサービスのドメイン単位(Shop、Finance、Commonなど)で設定します


プロジェクトの設定
  • 本番、ステージング、開発環境など環境ごとに作成することが一般的です
  • プロジェクトはAWSでいうとアカウントに当たるため、基盤ポリシー、利用請求毎に作成する
  • 本番環境のみ高セキュアなポリシーのプロジェクトに配置し、その他開発、検証環境等は低ポリシーなプロジェクトに設定


6. IaC

※ IaCツールには一般的にTerraform を使うことが多いため、Terraformベースで記載する


Terraformを使う上での基本方針

Terraformを使う際には以下のような方針で開発を行う

# 基本方針 説明
1 エディタはVSCode 無料、他言語でも利用、多機能のため
2 terraform fmtを必ず使う VSCodeで常に統一した記載を心がけましょう
3 静的解析ツールにはtfsec
4 専用テスト環境を用意しましょう Terraformを商用利用する際は必ずテスト環境で動作確認してからリリースしましょう
5 Providerバージョンは固定させましょう 利用するクラウドのProviderやその他ミドルウェアなどのバージョンは互換性問題を防ぐため固定させましょう


Terraformのリポジトリは目的毎に分ける

マイクロサービス自体もそうですが、Terraformは目的毎に分けましょう。大規模になると、それぞれのサービス毎やインフラ毎にチームを作り、それぞれ独立して開発を進めるため、リリース影響範囲等を明確に分割しましょう。

アンチパターンとして、NWとFW、LB、GWなどのインフラ系を全て同じTerraform又はリポジトリ上に書くのは影響や管理面の問題で避けた方が良いでしょう。


7. データストア・データベース


データストアとデータベースの使い分け

データを格納する際はファイル、データ(データストア)のいずれかの形式で格納するのかを検討する必要があります。 ファイル転送などで利用するのであればファイル形式でも構いませんが、必要なければ基本はデータ形式で格納した方が高速かつ無駄な処理を回避できます。

そのため、以下のようにまとめられます。

サービス 選定観点
GCS ファイルにてデータ転送が必要な場合に利用
Firestore 他データとの整合性を必要としないデータ保管且つフルマネージドでもありシンプルなNoSQLのためこちらを選定する
CloudSQL 複数テーブルのデータとして保管が必要且つの整合性利用
Memcache JWT内UUID値など軽量な情報を保管する場合に利用
SecretManager 鍵情報やパスワードなど漏洩を防止したい内容が含まれている場合に利用
  • 鍵情報やパスワードなど漏洩を防止したい内容が含まれている場合
    • SecretManagerを選定
  • 鍵情報やパスワードなど漏洩を防止したい内容が含まれていない場合
    • ファイルにてデータ転送が必要な場合
      • GCSを選定
    • データとして保管が必要な場合
      • データの整合性が必要なく低コストを優先したい場合
        • Firestoreを選定
      • 複数テーブルが必要でデータの整合性が必要である場合
        • コスト優先ならCloudSQLを選定
        • パフォーマンス優先ならAlloyDBを選定
        • 複数リージョンでの整合性を必要とする場合
          • Spannerを選定
    • リアルタイムで高速書込読込が必要で場合
      • Memcacheを選定


Firestoreのモード使い分け

Firestore にはネイティブモードとDatastoreモードの2種類あるが、ネイティブモードはリアルタイムアップデート機能によりモバイルアプリと相性が良い。Datastoreモードは通常のWebアプリなどで利用する。
ただし、これらのモードはプロジェクト毎にどちらかの設定であるため慎重に選択すること。変更する場合はストアの情報を初期化する必要がある。


マイクロサービスにおけるデータストア・データベース利用の注意点
  • データストアやデータベースへのアクセスは必ず1つのマイクロサービスで行うことで複数組織による責任を明確にすることによって、デグレデッドロックを防ぎ結果整合性を実現します
  • 利用用途によって適したDBを選定すること
  • 機密性の高い情報を扱う際には公開範囲の設定を検討すること
  • データ保持期間(TTL)を明確にすること


8. インフラセキュリティ


マイクロサービスにおけるデータ保護

マイクロサービス基盤にてデータ保護のために工夫することは以下になります。

  • セキュアな情報はSecretManagerを必ず使い、利用回数を最低限とする
  • JWTなどのフロントにセキュアな情報を出さないようにバックエンドを工夫する
  • データ保護はフルマネージドサービスを中心に利用することにより、無駄なセキュリティリスクを抑制します


コンテナイメージを考える

セキュリティ観点でコンテナベースイメージには以下のような対策を実行します。

  • ベースイメージにはオフィシャルを利用し、それ以外のイメージは利用しない
  • Alpineを選定し、内包ライブラリを最低限にする
  • Dependabotなどで依存関係にあるパッケージの脆弱性検知を行う
  • Artifact Registryによるコンテナ脆弱性スキャン機能の利用

高速ビルドを意識する場合は主に以下を考慮します。

  • レイヤー キャッシュを意識したDockerfileを作成する
  • dockerコマンドのビルドキャッシュオプションを利用する


Cloud Service Meshのセキュリティ
  • GCPセキュリティに必要なベストプラクティス以下になります

cloud.google.com


9. 監視・モニタリング


監視のイメージ

特に大規模なマイクロサービスの場合、膨大なコンテナのログから状況を把握することは重要となる。そのため一般的には統合監視可能なツールを取り入れ、管理を容易にします。

  • GCPの場合様々な指標の情報を統合的にモニタリングする場合はCloud Monitoringを利用
  • メッシュ内の通信経路、速度、ステータスに関してはServiceMeshのダッシュボード(Anthosなど)
  • マイクロサービスにおけるフロントから各コンテナのトレース情報は Cloud Trace


APIリクエストをどのようにトレースするのか(トレーサビリティ)

Cloud Service Mesh であれば Cloud Trace を利用して顧客リクエストをトレースデータをモニタリングできます。

https://cloud.google.com/service-mesh/docs/observability/accessing-traces?hl=ja#managed-td


10. レジリエンス


トラフィックへの対応


マシントラブルへの対応
  • コンテナによる冗長構成
  • ゾーン冗長
  • サーキットブレーカー


自然災害対応について
  • リージョン冗長は基盤を倍持つ必要があるため、大規模基盤や重要基盤にのみで検討する
  • リージョン冗長のためにAct-Act を検討することにより、高トラフィックによるレジリエンスを向上させられる
マイクロサービスにおけるリトライ処理注意点
  • マイクロサービスでは1リクエストにつき、複数コンテナでリトライ処理が考えられますが、その場合無邪気に全てのコンテナでリトライをしてしまうと、アクセス負荷が爆増してしまいます
  • 1リクエスト毎の最大リトライ回数を設定するため、API-Gatewayでリトライを設定する


11. テスト


モックツール

単体テスト結合テストなど対向先との連携テストのためモックツールを利用します

  • WireMock
  • Mockoon


負荷テストツール


Pact
  • 結合テストにおいてPactにてサービス間テストを行うことで、各サービスが提供するAPIの入出力の仕様を契約として明確に定義し、サービス間の連携が正しく行われているかを確認できます。


12. パフォーマンスチューニング


主なパフォーマンス改善例
  • フロントキャッシュ(storeなど)による情報取得時間改善
  • 通信シーケンス見直し・削減による改善
  • KeepAliveによる通信改善
  • 性能チューニングによるパフォーマンス改善


13. DevOps


GCPにてGithub Actionsの利用について

Github Actionsにてパイプラインを起動する際、サービスアカウントではなくWorkload identityを利用することにより、ID等の漏洩を防ぐことができる。その他GCPとの外部連携にはWorkload Identity を利用することがセキュリティベストプラクティス。


リリースパターン

マイクロサービスにおいて主に以下リリースパターンを実装することにより、俊敏で安全なリリースを目指します。


DBにおける後方互換性について

RDBにおいてたとえばカラムの設定変更等を行ってしまうと、それまでカラムを利用していた別バージョンのマイクロサービスに影響が出てしまいます。そのためRDB後方互換性を持たせたリリースを行うには、更新ルールを設ける必要性があります。

  • DBのカラムやインデックスなど設定を更新する場合、更新はせず、追加で対応すること
  • 基本削除設定は行わないこと
  • RDBの更新や削除は参照しているマイクロサービス全バージョンに影響が出ないことを確認した上で行うこと

これらのルールが守れない場合は基本的にはRDBを使わずKeyValue のNoSQLを利用します。


14. よくあるマイクロサービスアーキテクチャでの検討


特定のトラフィックだけを通すアーキテクチャパターン

コストをかければVPNなど検討できますが、不特定多数のアクセスを想定する場合は Cloud Load Balancer(XLB)にてクライアント証明書を設定します。 それにより証明書をインストール済みの端末のみ環境にアクセスが可能になります。 自己認証局をデプロイすれば証明書自体はフリーで作成可能のため、低コストで実現が可能となります。


非同期処理について

非同期処理のためゼロスケーリング可能なCloudRunやFunctionsなどを利用することでコストを最適化できる

利用サービス名 説明
Cloud Scheduler 非同期にタスクを実行する場合は基本スケジューラを利用する
Cloud Workflows Workflowsを使わない設計パターンも考えられるが、複数の処理実行の場合は1処理毎で分割することにより、テストの容易化やデバッグの容易化のため、導入はベストプラクティスとなる。またWorkflowsにてタイムアウトやリトライなどの制御が可能
Cloud Run Cloud Functionsを使うこともできるが、専用パイプラインを作る必要がある。Cloud Runであればジョブ実行も可能のため、選定サービスを不用意に増やす必要がなくなる。


GCSからのファイル転送

GCSから特定箇所にファイル転送する方法はいくつか方法がありますが、

利用サービス名 説明
Cloud Run Cloud Runのジョブを利用してgcloud storageコマンドを実行することにより容易にファイルを転送できます。別途設計パターンは考えられますが、一番低コストで実現できます


GCSの設計イメージ

GCSにファイルを格納する場合、バケットにて分けて格納するか、フォルダに分けて格納するかの2パターンが考えられます。複数サービス・プロダクトが乗るがマイクロサービス基盤では、1プロダクト毎にバケットを分ける方がアクセス権限がシンプルに分割できるため利用しやすいと言えます。