Dapr Advent Calendar 12日目 - Daprをk8s以外の分散環境で使う
こんにちは Dapr Advent Calendar 12日目です。昨日は @tmak_tw さんの Daprの回復性を支える仕組み 現状と展望 でした。実際に僕もインフラ側の問題起きた時にDaprを使ったアプリが自動的に復旧しない*1とか、サーキットブレイカーパターンが使えないとか、その辺りに課題感を感じていたので興味があるエントリーでした。
さて、今回からは「分散環境編」です。
Daprの運用環境を考える
これまでのエントリーでは、ローカルの開発環境でDaprを使ってきました。これを運用環境や試験環境で、複数台のサーバでクラスタリングして動作させるにはどうすれば良いのでしょうか。
Daprのドキュメントなどでは、基本的にk8sを使うことが推奨されています。実際に僕もk8s(Amazon EKS)上で運用しており、k8sを使ったのは初めてだったものの噂に聞いていたほどは難しくなく、意外と扱いやすいなと思いました。とは言え、k8sを使うことにまだまだ抵抗がある人も多いと思います。
分散環境編の1回目は、まずk8sを使わずにDaprのシステムを運用する方法を考えてみます。
分散環境の何が問題になるのか?
ローカルPCでの開発から、分散環境(特にクラウド)になることで、何が困るのか整理してみましょう。
この2つです。
この2つの問題以外はDaprの設定ファイルに従って外部のサーバやサービスを利用するため、特に問題にはならないはずです。もちろん設定ファイルやアプリケーションのデプロイが面倒だという問題はあるでしょうけど、それはDaprの運用特有の問題ではありません。
では、この問題の解決方法を1つずつ考えていきましょう。
DockerなしでDaprを利用する
まずは1つめ、Daprの運用にDockerが必要となる件なのですが dapr without docker
でググると、あっさりこんなドキュメントが見つかりました。
How-To: Run Dapr in self-hosted mode without Docker | Dapr Docs
Daprの初期化を dapr init --slim
というオプション付きで実行すれば、DockerなしでDaprをインストールできるようです。RedisやZipkinはインストールされませんが、必要であれば別に立てるでしょうから問題はありませんね。
何だかあっさり解決してしまいました。
名前解決をどうするか
そして2つめの名前解決についてです。これに関して、このドキュメントを見ると、
Service invocation overview - Round robin load balancing with mDNS | Dapr Docs
名前解決のためのmDNSに関して、こんな記述がありました。
These instance can be on the same machine or on different machines.
複数のマシンでも問題なく動くそうです。今回はこれを試してみましょう。
複数のPCでDaprを動作させる
それでは2台のPCで、それぞれDockerなしでDaprを動かしてみることにします。2台もPCを用意できない人は、ピザでも食べながらこの続きを読んでください。
Daprのアンインストール
これまでDaprを使っていた場合は、いったんDaprをアンインストールします。
dapr uninstall
また、残っているDockerコンテナも停止します。
docker stop `docker ps -q --filter name=dapr_` docker rm `docker ps -aq --filter name=dapr_`
さらに ~/.dapr
もフォルダごと削除しました。
これでアンインストールは完了です。
Daprをスタンドアロンモードで初期化
続いて2台のPCでDaprをセットアップします。
Dapr CLIが入っていない場合は、ドキュメントに従ってDapr CLIインストールします。
続いてDaprをスタンドアロンモードで初期化します。
dapr init --slim
インストールが完了したら、Dockerコンテナの一覧を見てみます。
docker ps -a --filter name=dapr_
出力結果はこうなっているはずです。
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
通常のインストールではDaprやRedis、Zipkinなどのコンテナが作られたのですが、--slim
オプションつきの場合は作られませんでした。
またcomponentsディレクトリを見ると
ls ~/.dapr/components
どうやら空のようです。
設定ファイルも確認しておきましょう。
cat ~/.dapr/config.yaml
ファイルはできているのですが、中はこうなっています。
apiVersion: dapr.io/v1alpha1 kind: Configuration metadata: name: daprConfig spec: {}
何の設定もありませんね。
Dockerコンテナもなく、設定も最小限となっているDapr環境ができました。これを2台分セットアップします。
2台のPCでそれぞれアプリを起動してアクセス
それでは2台のPCでそれぞれアプリを起動してみましょう。
ソースコード
サンプルアプリケーションのソースコードはGitHubに置いてあります。
https://github.com/cero-t/dapr-advent-2021
今回はこのうち、3日目のエントリーで説明したInvokeの機能を使います。
2台で起動
まず1台目のPCでHello Worldのアプリケーションを起動します。
cd (GitHubのディレクトリパス)/dapr-advent-2021/hello dapr run --app-id hello-app --app-port 8080 ../mvnw spring-boot:run
そしてもう一台のPCで、Invokeアプリケーションを起動します。
cd (GitHubのディレクトリパス)/dapr-advent-2021/invoke dapr run --app-id invoke-app --app-port 8081 -- ../mvnw spring-boot:run -Dspring-boot.run.profiles=dapr
そして、invokeを起動した方のPCで、次のコマンドを実行します。
curl localhost:8081/invokeHello
結果が取得できたはずです。
{ "remoteMessage": { "message": "Hello, world!" }, "baseUrl": "http://localhost:58418/v1.0/invoke/hello-app/method" }
2台のPCで別々に動いていたアプリも問題なく通信ができました。
念のため、Hello WorldアプリケーションをCtrl + Cで停止させた後、もう一度アクセスしてみます。
curl localhost:8081/invokeHello
今度はエラーとなったはずです。
{ "timestamp": "2021-12-12T00:00:00.000+00:00", "status": 500, "error": "Internal Server Error", "path": "/invokeHello" }
Invokeアプリのコンソールにもエラーが出ているはずです。
== APP == 2021-12-10 00:00:00.000 ERROR 80260 --- [nio-8081-exec-6] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Internal Server Error: "{"errorCode":"ERR_DIRECT_INVOKE","message":"fail to invoke, id: hello-app, err: failed to invoke target hello-app after 3 retries"}"] with root cause
3回リトライしても hello-app
にアクセスできなかったというエラーです。つまり、別のPCで動いていたHello Worldにアクセスしようとしていたことが分かりますね。
別々のマシンであっても、DaprはmDNSを使ってアクセスができるようです。
AWSでも運用できるか?
Amazon EC2でDaprを動作させる?
ここまでで、2台のPCで通信できることは確認できましたが、同じことをAWSのEC2でもできるのでしょうか。
試しにやってみたのですが、残念ながら、EC2インスタンス上で動くDaprアプリケーションから別のEC2インスタンス上で動くDaprアプリケーションにはアクセスができませんでした。
mDNSはマルチキャストが使える環境でなければ使えないのですが、AWSのEC2ではマルチキャストが使えないため(たぶん)、mDNSで通信することはできないようです。Invoke API以外のAPIは使えるようなのですが、Invoke APIこそがDaprの要なので、それがなくては話にならないですよね。
また、mDNSの代わりにHashiCorp Consulを使えば良いようですが、僕がConsulに不慣れなので、ちょっと諦めてしまいました。
ちなみにAzureにはManaged HashiCorp Cosul Serviceがあったので、それで試してみようとしたのですが、画面に従ってインスタンスの作成を進めていただけなのに、Consulのインスタンス作成に失敗してしまい、カッとなって諦めてしまいました。無念。
Amazon ECSでDaprを動作させる?
EC2がダメなら、ECS(Elastic Container Service)ならどうか、と思って探していたところ、こういうIssueを見つけました。
AWS ECS name resolution component · Issue #1197 · dapr/components-contrib · GitHub
Issueを斜め読みした限りでは、ECSのサービスディスカバリを使うのではなく、外部DNSを利用できるようにすることで、ECSにも対応させようという試みのようです。この辺りがきちんと対応されれば、ECSで運用することもでそうです。
まとめ
- Daprの運用にDockerは必須ではない
- マルチキャストが使える環境であれば、mDNSを用いて複数のサーバ上でDaprを運用することができる
- AWSのEC2はマルチキャストが使えないためmDNSが使えない。Consulを使えば運用できる可能性がある
- AWSのECSにはいずれ対応されそう
という感じで、名前解決のところがもう少し強化されれば、k8sを使わずに運用することもできそうですね。SpringユーザーとしてはEurekaに対応してくれれば、サッとサーバを立てて運用できるのにな、と思うのですけどね。自分で実装するしかないですかね😇
そんなわけで、少し寄り道したような形になりましたが、次回からは王道のk8sを使った運用について説明していきます。
それでは、また!
2021-12-18 追記
アンインストール手順について、うらがみさんからコメントをもらいました。知らなかった!
この記事でDaprのアンインストール時に手動で残りのコンテナと~/.daprを削除していますが、dapr uninstall --allで全削除できるみたいです。
— うらがみ⛄ (@backpaper0) 2021年12月18日
rm -rf
コマンドをブログに書きたくなかったので、手で削除するなどと言ってごまかしてましたが、dapr uninstall --all
で削除するのが安全で良いですね。