MagicOnion+MemoryPack+YetAnotherHttpHandler on Azure Container Apps 構築のログ
動機
- だいぶん前にMagicOnionをローカル環境まで構築してほっぽっておいたので再度履修しておきたい
- MemoryPack触ったことないので今のうちに
-
ここはMessagePack for C#もSourceGenerator対応されたので、余裕があれば対応して比較もしたいまだプレリリース状態のようなので本当に余裕あれば
-
- YetAnotherHttpHandlerをリリース頂いたので、Unityでgrpc-dotnetをつかってみたい
- 業務でUnity+Grpc.Coreのプロトタイプ経験はあるが、結構もうげんなりしていたので
- 個人開発ならAzure使うだろし、今の業務でもDockerのそばで暮らしている感じなのでそろそろと思っていたところにAzure Container Apps に爆速でアプリをデプロイする を目にしてしまった
リポジトリ
まず、MagicOnionを普通にセットアップ。
参考にさせていただくのは下記。
Unity 2021.3.31f1 でプロジェクト作成して、先にgRPC関係のセットアップ。
YetAnotherHttpHandler はUPMのGit URLで追加し、依存先のライブラリも追加する。
今回は、下記の YetAnotherHttpHandler のReleasesに用意されているunitypackageを利用させていただいた。
MagicOnion を Ver.5.1.8 でセットアップ。
MagicOnion のunitypackage同梱のdllと、 YetAnotherHttpHandler で導入した Cysharp.Net.Http.YetAnotherHttpHandler.Dependencies.unitypackage
同梱のdllとで同じライブラリのDLL、 System.Runtime.CompilerServices.Unsafe.dll
が重複していたので、MagicOnion側のを削除。
一旦使用する想定はないものの、MessagePack for C# を導入していない状態で MagicOnion のunitypackage をインポートすると、MagicOnion.Abstraction
でMessagePack 名前空間のあれこれが結構参照されてしまっているようなので、ひとまずMessagePackも導入する。
このままだと、Grpc.Core を参照している箇所でエラーが出るので、 Scripting Define Symbol に USE_GRPC_NET_CLIENT
と USE_GRPC_NET_CLIENT_ONLY
を追加してRecompile走らせる。
これでエラーは発生しない状態までいけた。
Unityプロジェクトと同じリポジトリ内に .NET 7
のConsole Applicationのプロジェクトを作成。
az containerapp up
コマンドでDockerFile無しでのデプロイを試したいので、Docker Support
は一旦 Disable
。
作成したサーバー用プロジェクトに、NuGetで MagicOnion.Server 5.1.8 を追加。
この方法だと、 .gitignore
が追加されていないので、dotnet new gitignore
で追加。
ただ、Riderのコンソールだとうまくdotnet
コマンドが実行できなかったので、別でPowershellを起動して叩いた。
MemoryPack対応はmemorypack-supportを参照して対応。
MagicOnion.Serialization.MemoryPack
、Server側はNuGetで引けるが、ClientとなるUnity側では前述でインポートしたMagicOnionのunitypackageには同梱されていないようので、直接Githubのソースを引っ張ってくる必要がありそう。
5.1.8のラベルがついたソースからsrc\MagicOnion.Serialization.MemoryPack
以下のファイルをUnityプロジェクトへコピーする。
これでコンパイルエラーなどはなくなった。
上記から
Sever側は endpointOptions.Protocols = HttpProtocols.Http2;
Client側は handler.Http2Only = true;
で指定して、ローカルかつデバッグ実行でのUnaryは疎通確認OK
ASP.NET Core HTTPS 開発証明書 が認証されていないと、Sever側をビルドした後の起動時に怒られるので、
dotnet dev-certs https --trust
で認証しておく。(あくまでローカルでの確認用なので注意)
詳しい説明は、このあたりを参照
実際にデプロイしてインターネット越しでアクセスさせる場合は、DOTNET_GENERATE_ASPNET_CERTIFICATE
をfalseにしておくなどが良さそう?
一旦この状態で、デプロイしてどうなるかを試したいので、az containerapp up
を実行してみる
Azure CLIをインストールして
ログインして
az login
下記に従って、az containerapp
を利用できるようにして
az containerapp up
でDockerFileなしでのデプロイ実行
az containerapp up \
--name <CONTAINER_APP_NAME> \
--source . \
--ingress external \
--target-port 5000
リソースグループ、そしてその中に、コンテナー レジストリ、Container Apps 環境、Log Analytics ワークスペースが作成された。
(ちなみに上記だと作られるリソースグループのリージョンが West US 2 なので注意。)
が、Container Apps本体の作成前に、そもそものビルドでエラー。
Determining projects to restore...
Skipping project "/Shared/Shared.csproj" because it was not found.
Skipping project "/Shared/Shared.csproj" because it was not found.
/app/SampleService.cs(3,7): error CS0246: The type or namespace name 'MagicOnionTest' could not be found (are you missing a using directive or an assembly reference?) [/app/Server.csproj]
/app/SampleService.cs(7,46): error CS0246: The type or namespace name 'IConnectionTestService' could not be found (are you missing a using directive or an assembly reference?) [/app/Server.csproj]
/app/SampleService.cs(7,71): error CS0246: The type or namespace name 'IConnectionTestService' could not be found (are you missing a using directive or an assembly reference?) [/app/Server.csproj] | 1 | Please build your app locally before publishing. | https://docs.microsoft.com/en-us/azure/app-service/configure-language-dotnetcore?pivots=platform-linux
Unityの Assets\Scripts\Shared 以下に配置している共有用のディレクトリが上手く読み込めていないっぽい。
MagicOnion公式サンプルの形で、Shared用のcsprojを用意して回避できるか試す。
どうもうまくいかなかった(DockerFileでそれっぽくCOPYしてRestoreかけてもダメ)なので、
コマンド1つでうまくデプロイされてほしいところだが、一旦ほっておき、
SharedのDLLをdotnet publish
して、直接Server以下にコピーし、csprojで参照させることにした。
(まぁこの程度ならGitHub ActionsなりのCIでカバーできる範疇なのでギリ許容、とする...)
DockerFile置いたままだが、上記のコマンドに、すでに生成されてあるリソースグループとContainer Apps 環境を追加で指定してデプロイ。
az containerapp up \
--name <CONTAINER_APP_NAME> \
--source . \
--resource-group <RESOURCE_GROUP_NAME>
--environment <ENVIRONMENT_NAME>
--ingress external \
--target-port 5000
デプロイ後に、Client側で表示されるURLと指定ポートに書き換えて実行するも、
やはりTLS/SSL周りでダメなのか上手くリクエストが到達しないっぽく、下記のエラーになる。
(Azure Container Apps上のログストリームも、起動時以降ログが追記されない)
HttpRequestException: error trying to connect: tcp connect error: 接続済みの呼び出し先が一定の時間を過ぎても正しく応答しなかったため、接続できませんでした。または接続済みのホストが応答しなかったため、確立された接続は失敗しました。 (os error 10060)
ちなみにContainer Appsの挙動だが、上記コマンドでデプロイすると、HTTPスケールになっている。
レプリカの最小が0になっているので、最後のリクエストからしばらくたてば下記のように0になって自動で停止する。
この状態なら課金されないはず。
また、レプリカの最大が10ということで、これを変更したところ、ドキュメントどおりリビジョンの再作成が走った。
いちおうコストも確認したが、リクエスト自体が発生していない扱いになっている+リビジョン再作成は課金対象外で、
課金されていたのはレジストリに対してのみの模様。ありがたい。
リビジョン周りの参考
ちょっと放置していたので料金の確認。
レジストリのみの金額なものの、Container Appsを利用していたのは10/23辺りのみなので、Task vCPU Durationで課金されているのは不明。
(とはいえ、検証の範囲であれば十分安価)