- 0. はじめに
- 1. GCPベースでのマイクロサービス全体設計
- 2. UX/UI (Webアプリ、モバイルアプリ)
- 3. API
- 4. 認証/認可
- 5. インフラアーキ
- 6. IaC
- 7. データストア・データベース
- 8. インフラセキュリティ
- 9. 監視・モニタリング
- 10. レジリエンス
- 11. テスト
- 12. パフォーマンスチューニング
- 13. DevOps
- 14. よくあるマイクロサービスアーキテクチャでの検討
0. はじめに
GCPベースでマイクロサービス・ソリューションアーキテクトに必要なナレッジをまとめてみました。
本誌は随時更新し拡充・最新化していきたいと思います。
あくまで自身の考えをまとめたものになり、間違えや一部主観も含まれる可能性があるためご了承ください。
1. GCPベースでのマイクロサービス全体設計
マイクロサービス基盤において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. モバイルアプリ
モバイルアプリ開発にて考慮するべき点
モバイルアプリ開発において最初に考慮する点についてまとめる
項目 | 説明 |
---|---|
マルチプラットフォーム | モバイルアプリは特にiOSやAndroidなどの複数プラットフォームで展開することが一般的なため、コスト低減のためマルチプラットフォームに対応した言語を選定します。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の設定
サブネットの設定
- 一般的にはマイクロサービスのドメイン単位(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のセキュリティ
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. レジリエンス
高トラフィックへの対応
マシントラブルへの対応
- コンテナによる冗長構成
- ゾーン冗長
- サーキットブレーカー
自然災害対応について
マイクロサービスにおけるリトライ処理注意点
- マイクロサービスでは1リクエストにつき、複数コンテナでリトライ処理が考えられますが、その場合無邪気に全てのコンテナでリトライをしてしまうと、アクセス負荷が爆増してしまいます
- 1リクエスト毎の最大リトライ回数を設定するため、API-Gatewayでリトライを設定する
11. テスト
モックツール
単体テストや結合テストなど対向先との連携テストのためモックツールを利用します
- WireMock
- Mockoon
負荷テストツール
- JMeter
- Locust
Pact
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プロダクト毎にバケットを分ける方がアクセス権限がシンプルに分割できるため利用しやすいと言えます。