はじめに
本記事は、Microsoft Azure Tech
の Qiita
アドベントカレンダー の記事です。昔から存在は知っていたけどなんとなく難しそうなイメージがあり、なかなか手を出せていなかった dapr
ですが、今回はアドベントカレンダーということでしたので、思い切って勉強と開発をしてみました。dapr
ということでマイクロサービスごとは疎結合で連携されているため、Python
と JavaScript
という技術スタックが異なるコンテナーが動くマイクロサービスを構築してみました。構築後は、Azure Container Apps
にデプロイするところまでを記事にまとめています。本記事では、まず初めに dapr
や Azure Container Apps
などの説明をした後、構築したマイクロサービスのデモと説明をします。そして最後に、マイクロサービスのデプロイ手順について紹介します。
マイクロサービスアーキテクチャとは
マイクロサービスアーキテクチャとは、大規模なアプリケーションを小さな独立したサービスに分割した構成のことです。マイクロサービスアーキテクチャを使用することで、システム全体の機能のコア領域を個別に開発、アップグレード、バージョン管理、スケーリングできるようになります。これにより、迅速な開発と保守が可能で、異なる技術スタックを利用できるため、効率的で柔軟性の高いアプリケーション開発が実現されます。
上の図は、モノリシックなアプリケーションとマイクロサービスアプリケーションの違いを概念図として比較したものになります。モノリシックなアプリケーションは、Web
3 層構造などの、Web
、ビジネス、データなどの、機能層で分割された構造となっています。クラウドの導入が進み、従来のこうしたモノリシックなアプリケーションは、マイクロサービスアプリケーションアーキテクチャに向かう傾向にあります。マイクロサービスアプリケーションは、個々が小規模な個別サービスなので、あらゆる言語、あらゆるフレームワーク、バージョン、デプロイ、拡張、が可能で自由度が高いですが、複雑性が増すという課題もあります。次の見出しで紹介する dapr
はこうした分散システムの複雑性を軽減することが可能です。
dapr とは
dapr
(Distributed Application Runtime
)は、分散システムの開発を容易にするためのオープンソースのランタイムフレームワークです。異なるサービスのコミュニケーション、状態管理、エベント処理などの共通機能を抽象化し、開発者がアプリケーションを構築する際の複雑さを軽減します。様々なプログラミング言語やクラウドプラットフォームで利用可能であり、柔軟で拡張可能な分散システムの構築が可能です。dapr
では、マイクロサービスアプリケーションを構成要素と呼ばれる独立した API
に構築するための仕組みが体系化されています。dapr
の機能について、以下で簡単にまとめます。
-
Service-to-service Invocation
- サービスの呼び出しのためのエンドポイントが作成され、他のサービスとの連携を容易に実現
-
State Management
- テートフルなサービスをに対応し、状態データを保存可能
-
Publish and Subscribe
- サービス同士の
Publish-Subscribe
メッセージングを実現可能
- サービス同士の
-
Input/Output Bindings
- 外部のイベントによるアプリのトリガーと、入出力インターフェイスが利用可能
-
Actors
-
Actor
パターンにより、サービス同士の連携が可能
-
-
Secrets
- 機密データを格納したストレージに接続してアクセス可能
-
Configuration
- アプリケーションに関する設定情報が登録可能
-
Distributed Lock
- ロックをしてリソースへの排他的なアクセスが可能
-
Workflows
- ビジネスロジックと統合を簡単に記述し、マイクロサービスの調整が可能
-
Cryptography
- 暗号化キーをアプリケーションに公開することなく、暗号化操作を実行可能
Azure Container Apps とは
Azure Container Apps
は、コンテナー化されたアプリケーションを実行するためのサーバーレスプラットフォームです。Azure Container Apps
を利用することで、保守するインフラストラクチャが少なくなるため、運用コストを削減できます。Azure Container Apps
は 1 つ以上のコンテナーで作られたコンテナーアプリで構成されるため、個々がマイクロサービスとしての役割を果たします。
Azure Container Apps
の一般的な用途には以下になります。
-
API
エンドポイントのデプロイ - バックグラウンド処理ジョブのホスティング
- イベント駆動型処理の処理
- マイクロサービスの実行
Azure Container Apps
は、Container Apps Environment
と呼ばれるセキュリティ境界内にデプロイされます。また、Azure Container Apps
は、スケーリング、バージョン管理、アップグレード、サービス検出、ネイティブの dapr
統合、といったマイクロサービスをデプロイする基盤を提供しています。
サンプルアプリの紹介・デモ
サンプルアプリのデモ動画を Twitter
に載せました。このサンプルアプリは、りんご・ばななの在庫個数をリアルタイムで表示する Web
アプリになっています。サンプルアプリの仕様として、りんご・ばななの在庫はそれぞれ 1000 個ずつあり、りんごは 1 秒ごとに 1 個 から 10 個の間の乱数、ばななは 2 秒ごとに 1 個 から 20 個の間の乱数の注文が入るようにするため、りんご・ばななの注文サービスは定期的に dapr
に向けて POST
通信をするようにしています。このアプリの全体像を伝えるために、ブラウザで動く Web
アプリだけを録画するよりも、他のマイクロサービスで出力されるログを同時に確認できたほうが、サービス全体の動きを理解しやすいと思うので、Visual Studio Code
の画面でブラウザと複数のコンソール画面をまとめて 1 画面に録画しました。左上が React
による在庫個数を表示したフロント画面であり、中央上が Worker1
によるりんごの注文ログ、右上が Worker2
によるばななの注文ログを表示しており、下が Service
によるりんごとばななの受注ログ・在庫個数ログになります。
サンプルアプリのソースコードは以下の GitHub
リポジトリに公開しています。
サンプルアプリは以下のソースコードを参考にして開発しました。
アーキテクチャ
構築したマイクロサービスアプリケーションのアーキテクチャ図は以下になります。Azure Container Apps Environments
内に 5 つのマイクロサービスをデプロイし、それぞれに対して Azure Container Apps
でホスティングしています。マイクロサービスはそれぞれ Docker
でコンテナ化されており、その横にサイドカーとして動く dapr
が配置されています。dapr
間は gRPC
で通信しており、dapr
とサーバー間は HTTP
もしくは gRPC
で通信をしています。それぞれのサービスで公開しているポート番号や通信経路は以下の図にまとめています。一方で今回はサンプルなので、Vnet
による閉域化などの細かい設計はしていません。また、イングレスについても図にのせていませんが、イングレスエンドポイントは常にポート 443 で公開されています。
gRPC
は、HTTP/2
によって高速化された通信が可能で、クライアントとサーバー間での双方向なストリーミング通信ができます。
ローカルと Azure
では、起動しているアプリケーションは構造は同じですが、公開ポートなど若干異なる点があります。また、マイクロサービスごとの名前、フレームワークと言語、役割についてそれぞれ以下の表にまとめます。
マイクロサービス名 | マイクロサービスのフレームワークと言語 | 役割 |
---|---|---|
Web(front) | React(JavaScript) | りんご・ばななの在庫個数の表示画面 |
Web(backend) | Express(Node.js) | りんご・ばななの在庫個数伝達サービス |
Service | Flask(Python) | りんご・ばななの受注と在庫管理サービス |
Worker1 | なし(Python) | りんごの注文サービス |
Worker2 | なし(Python) | ばななの注文サービス |
また、果物の個数が更新されるまでのデータフローは以下になります。
-
Worker1
とWorker2
がdapr
に向けて果物注文のためのPOST
リクエストを行います -
dapr
間でgRPC Request
が行われ、dapr-Service
間でHTTP
通信が行われます -
Service
で在庫数を変更した後、Service-dapr
間でHTTP
通信が行われます -
dapr
間でgRPC
通信が行われた後、Web backend
へHTTP
通信が行われます -
Web backend
とWeb frontend
はWebSocket
で繋がっており、HTTP
通信が行われます -
Web frontend
で果物の在庫個数が更新されます
ローカル実行
サンプルアプリの紹介・デモでは、ローカル実行した様子を録画したものを載せています。dapr run
を実行して dapr
を使用するには、どうやら以下の 3 パターン方法しかないようだったので、ローカルで実行するときはアプリと dapr
はプロセスとして起動し、コンテナーは利用しませんでした。当然、Azure Container Apps
にデプロイする際には Docker
コンテナ化する必要がありますが。
- アプリと
dapr
をプロセスとして起動する方法 - アプリがプロセスで
dapr
をDocker
コンテナとして起動する方法 - アプリと
dapr
を 1 つのDocker
コンテナ内で起動する方法
ローカル実行をするためのコマンドは サンプルアプリを公開している GitHub リポジトリ の README.md
にまとめているので必要であればそちらをご確認ください。
デプロイ
ローカルで実行したマイクロサービスアプリケーションのデプロイは、以下の公式ドキュメントを参考にして Azure CLI
にて実行しました。コマンドの詳細についてはローカル実行と同様に、 サンプルアプリを公開している GitHub リポジトリ の README.md
にまとめているので必要であればそちらをご確認ください。
デプロイ結果
Webfrontend のフロント画面
Webbackend のログ
service のログ
worker1 のログ
worker2 のログ
無事、デプロイができました。
おわりに
初めて、dapr
に挑戦してみて戸惑う点も多かったですが、慣れてくると確実に便利な技術だと感じました。今回のマイクロサービスアーキテクチャでは dapr
コンポーネントは扱わず、サービス呼び出し機能しか扱いませんでしたが、PubSub
や Secret
や Bind
など、他にも dapr
には数多くの機能があるので、試してみようと思います。