この記事は Dapr に関する一連の記事の一部です。
- Dapr って何? - 概要編
- Dapr を使ってみる - 入門編
- Dapr を使ってみる - State management 編
Dapr とは
公式ページからの説明によると Dapr(The Distributed Application Runtime)とは
安全で信頼性の高いマイクロサービスを構築するためのAPI
となります。
API 対応した各種言語用の SDK があるため、.NET だけではなく様々な言語で使用可能です。
Dapr Software Development Kigs(SDKs)
そして機能が少しずつ増加しており、2024/4時点で10+3の機能があります。
https://docs.dapr.io/concepts/overview/
初見ではなんのために存在し、どう便利なのか、そしてどう使うのかさっぱりわからないと思います。誤解を恐れずにいうと、
Dapr とはインフラレイヤーの抽象化
です。ここから派生して様々な機能を持つようになっているので、この理解だけでは Dapr 全てを説明しきれないのですが、出発点は間違いなくここです。抽象化、というとわかりにくいかもしれません。別の言い方をすると
Dapr とはアプリケーションのインフラレイヤーへの依存を排除するもの
です。アプリケーションがインフラへの依存が無くなると、アプリケーションが使用する特定リソースの切り替え時にアプリケーションを修正する必要がなくなります。例えば DB の種類を変えたり、オブジェクトストレージの種類を変更したとしてもアプリケーションに変更は発生しません。
これによって、例えばローカルと本番との間での環境の差異を Dapr が吸収してくれます。ホスティングするクラウドを変更する場合でも同様です。
難しい言い方をするとインフラレイヤーへの依存が無くなることで、サービス(アプリケーション)の独立性と可搬性が劇的に向上します。
ではどうやって依存を排除するのか、どう使うのかを具体的な例から理解していきましょう。
Dapr の読み方
ちなみに Dapr の読み方ですが、英語発音ではダパーです。もしくはダーパーです。ダッパーとは読まないように注意しましょう。 Dapper という歴史ある軽量ORマッパーと誤解します。
インフラレイヤーを抽象化する具体例
では、例を見ながら Dapr がどういうものなのかを理解していきましょう。
Dapr によるサービス間の呼び出し
例えばマイクロサービスのように自分たちで構築中のサービスが複数あり、それを呼び出し合っているとします。通常、その呼び出しは URL などを用いて直接相手を呼び出します。
ServiceA は ServiceB の URL を知らなければ呼び出すことができません。SerivceA は ServiceB に依存している、といえます。Dapr を導入するとこの依存を完全に排除することができます。
Dapr を使用する場合は次の構成になります。
サイドカーパターン
Dapr はサイドカーパターンを採用しています。
Kubernetes であれば同一 Pod の中に、Azure Container Apps(ACA)であれば同一アプリの中に Dapr のコンテナを立ち上げます(セットアップが必要です)。つまり、ServiceA から見ると同一ホスト内部に別プロセスで Dapr アプリケーションが立ち上がっています。そのため、アプリケーションと Dapr 間の通信は常に localhost:xxxx となります。
ServiceA からの呼び出し
図のように ServiceA から ServiceB への呼び出し時、送信先を明示的に Dapr サイドカーコンテナにします。この時、呼び出し先である ServiceB の Dapr コンテナに付けておいた appid、serviceB を使って呼び出します。すると、Dapr は自動的に名前解決を行ってサイドカーコンテナ間で通信します。
つまり ServiceA 側の Dapr コンテナは Proxy だと考えれば良いのです。
呼び出される ServiceB
次に呼び出しを受ける側の ServiceB 側の Dapr コンテナですが、通信を受信したらトラフィックを ServiceB に流します。そのため、ServiceB の Dapr コンテナは立ち上げ時に ServiceB のポート番号 8080 を知っている必要があります。
つまり ServiceB 側の Dapr コンテナは ReverseProxy だと考えれば良いのです。
おさらい
おさらいすると、ServiceA は ServiceB を呼び出す時に、appid が serviceB である Dapr コンテナを呼び出します。実際に ServiceB を呼んでいるかどうかは ServiceA にはわかりません。依存関係がここで完全に排除されます。
ServiceB は Dapr 用の特別な対応は不要です。Dapr コンテナを立ち上げる時に自分のポート番号を Dapr コンテナに渡しておくだけです。
Dapr によるサービス呼び出しはこちらが公式ページです。
Dapr による状態保存
Dapr にはアプリケーションの状態を保存することができる State management という機能があります。
セッション情報やキャッシュ、ショッピングカートなど一時的な状態保存や、ワークフローのような比較的長時間に渡るフローの状態保存に用いることができます。
このような場合、通常は次のようにアプリケーションから直接永続化アプリケーションまたはサービスを利用します。
ServiceA は特定の種類の永続化アプリケーション(サービス)に依存しています。これが Dapr を使用すると、次のようになります。
ServiceA は 自身と同じホストで稼働する Dapr コンテナに対して、POST/GET リクエストします。すると、Dapr コンテナは事前に定義された永続化アプリケーション(サービス)に対して保存・読み出しを実行します。
おさらい
ServiceA は Dapr コンテナに対してのみ要求を出して、Dapr コンテナが実際にどの永続化アプリケーション(サービス)に対して処理を行っているのかはわかりません。依存関係が完全に排除されています。
使用可能な永続化サービス
State management に使用できる永続化サービスはとてもたくさんの種類が用意されています。SQL Database, PostgreSQL, MySQL, MongoDB, Redis などの代表的なデータベース、NoSQLはもちろん、Azure はもちろん AWS や GCP, Oracle Cloud などのサービスにも対応しています。
詳しくはこちらをご参照ください。
改めて Dapr とは
Dapr とはアプリケーションにとって、インフラレイヤーへの依存を完全に排除するところからスタートしました。そしてそれを実現するために Sidecar パターンを採用しています。Sidecar パターンを採用してインフラレイヤーを抽象化することで、実に様々な機能にコードベースで対応できるようになっています。
Dapr では機能のことを Building Block と呼んでいます。以下が2024年4月現在で公開されている Building Block です。
-
Service invocation
- 上で説明したサービス呼び出しです。
-
State management
- 上で説明した状態管理のサービスです。
- State store component specs
-
PubSub
- いわゆる配信・購読モデルです。ブローカーと呼ばれるメッセージ配信サービスへの依存を完全排除できます。
- Pub/Sub brokers component specs
-
Bindings
- イベント発火時に呼び出される Input/Output-Binding を実現します。Queue, Messaging, Storage, NoSQL, SMTPなど多種多様なイベントに対応しています。Httpでの呼び出しの場合は Binding ではなく上の Service invocation を使います。
- Bindings component specs
-
Actor
- Orleans でも採用されている Virtual Actor モデルを実現します。
-
Secrets
- クラウドでは接続文字列などのシークレット情報をマネージドのシークレットサービスを使用しますが、Dapr の Secrets を使用することで特定のマネージドサービスへの依存を排除できます。
- Secret store component specs
-
Configuration
- 各アプリケーションが参照する構成ストアへの依存を完全に排除できます。構成ストア内のデータが変更されると、新しい変更を読み込むように通知されます。
- Configuration store component specs
-
Distributed lock
- データベースやキューのような状態が変化するリソースに対して、アプリケーションから Lock することで競合が発生しないようにする仕組みを提供します。
- Lock components specs
-
Workflow
- Input/Output Bindings, PubSub, Serivce invocation, Actor など複数の Building Block を駆使してワークフローを実現します。
- まだベータ版です。(2024年4月現在)
-
Cryptography
- データの暗号・復号を行う際のキーをアプリケーションで保持することなく、マネージドなキーコンテナにアクセスして暗号・復号処理します。これもまた特定のマネージドなキーコンテナーサービスへの依存を排除するものです。
- Cryptography component specs
Dapr とはサービスメッシュのこと?
ここまでの説明で、Dapr とは要するにサービスメッシュに近いのでは?と思われた方もいらっしゃるでしょう。
サービスメッシュとは、各マイクロサービスの Sidecar コンテナとして構成され、 Sidecar 同士が通信するアーキテクチャです。Sidecar にサービスディスカバリやサービス呼び出し時の負荷分散、リトライやサーキットブレーカーなどの回復力機能を持たせることで、マイクロサービスが共通して持つ課題に対応しよう、というものです。代表的なものとして Istio, Envoy などがあります。
Sidecar アーキテクチャを採用して、Sidecar コンテナ間で通信をするという点で Dapr とサービスメッシュは同じです。そして Dapr はサービスメッシュの機能と一部重複します。しかし、方向性が異なります。サービスメッシュはインフラレイヤーでの課題解決を図るものですが、Dapr は開発者に委ねられます。
そのため、トラフィック分割などのネットワークに関する機能を Dapr は持っていません。必要に応じてサービスメッシュと組み合わせて運用することもあります。詳しくは次のページを参照してください。
まとめ
Dapr とはアプリケーションからインフラレイヤーへの依存を排除するために Sidecar パターンを採用しており、それをベースに様々な機能が追加された開発者のためのサービスです。一言で言えば、
Daprとは、インフラレイヤーの抽象化
です。Dapr をちょっと使ってみようかな、と思っていただけたら幸いです。