AWS App Runner に Blazor Server アプリケーションを載せてみた

## はじめに

先日、福岡で開催されたコミュニティイベント Fukuoka.NET #25 に参加させて頂いたのですが、

https://fukuten.connpass.com/event/297072/

その際に、AWS App Runner 上に ASP.NET Core アプリケーションをデプロイする方法を習いました。

AWS App Runner は、Amazon が提供するクラウドサービス Amazon Web Service が提供するサービスのひとつで、"仮想マシンへの実行環境の構築" みたいな手間を掛けることなく、Web アプリケーションを手軽にホストしてくれて、かつ、GitHub 等と連携してソースコードからのビルド・デプロイにも対応してくれるサービスらしいです。

https://aws.amazon.com/jp/apprunner/

自分の中では、Heroku とか Azure App Service の AWS 版、と理解しています。で、この AWS App Runner がサポートしている言語・処理系に .NET が含まれているとのことでした。

そこで自分でも実際に、ASP.NET Core Web アプリケーション、とくに Blazor Server アプリケーションを AWS App Runner 上に載せてみました。

今回はお試しということで、自分の GitHub リポジトリから手動で AWS App Runner 上へ配置 (デプロイ) する構成で、AWS App Runner 上に Blazor Serevr アプリケーションを配置することでやってみました。

## Blazor Server アプリケーションの新規作成

まずは、これから AWS App Runner に配置する、サンプルの Blazor Server アプリケーションを、自分の PC 上で新規作成することにします。

AWS App Runner がサポートしている .NET バージョンは、LTS (Long Term Support, 長期サポート) バージョンだそうです。試した当時は、2023 年 12 月時点の最新 LTS バージョンである .NET 8 がリリースされる前でしたので、そのひとつ前の LTS バージョン、すなわち .NET 6 を対象フレームワークとすることにしました。

Git コマンド、および、.NET SDK のバージョン 6 を自分の PC にインストールした状態で、以下のコマンドをターミナル上で実行し、カレントフォルダに Blazor Server アプリケーションプロジェクトを新規に生成します。

```shell
dotnet new blazorserver -f net6.0 -n MyBlazorServerApp -o .
```

ちなみに、.NET SDK バージョン 6 がインストールされている限り、例え現在のターミナルでの既定の dotnet コマンドのバージョンがバージョン 6 より後のバージョン、バージョン 7 や 8 であったとしても (下記コマンドのように、`dotnet --version` コマンドでわかります)、

```shell
dotnet --version
```

`dotnet new` コマンドの実行時に `-f net6.0` のコマンドラインオプションで対象フレームワークバージョンを指定することで、.NET 6 の Blazor Server アプリケーションプロジェクトを新規作成することができます (`global.json` による、使用する .NET SDK バージョンの固定は、必ずしも必要ありません)

## Git ローカルリポジトリの作成とコミット & プッシュ

続けて、下記コマンドで .NET アプリケーションプロジェクト用の `.gitignore` ファイルを生成しておいて、

```shell
dotnet new gitignore
```

Git ローカルリポジトリをこのフォルダで作成・初期化し、作業フォルダ内のソーコードファイル群をコミットします (下記コマンド)。

```shell
git init .
git add .
git commit -m "初回コミット"
```

## GitHub リポジトリの作成とプッシュ

別途、このサンプルアプリケーションのソースコードを収録する Git リポジトリを GitHub 上に作成し、そのリポジトリ URL を入手しておきます。

その上で、下記コマンドで Git ローカルリポジトリの内容をその GitHub 上のリポジトリにプッシュします。

```shell
git remote add origin <ここに GitHub リポジトリの URL>
git push origin main -u
```

以上で、GitHub リポジトリ上に、AWS App Runner 上に配置する Blazor Serevr アプリケーションのソースコード一式が掲載されました。

## AWS App Runner の構成

ではいよいよ、AWS App Runner への配置を進めていきます。

Web ブラウザで AWS コンソールにサインインし、検索ボックスに "App Runner" と入力して App Runner のコンソールを開き、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/1bb527af-8302-be23-69b7-ddc18fb48c21.png)

[サービスの作成] をクリックして、新たな App Runner による Web アプリケーションサイトの作成を始めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/56677c03-af43-95de-a8f8-e50c88d55b08.png)

### ソースおよびデプロイ

すると「ソースおよびデプロイ」というページに移動します。

今回は GitHub リポジトリからの配置ですから、[リポジトリタイプ] は「ソースコードリポジトリ」を選択し、[プロバイダー] は「GitHub」を選択します。その上で、自分の GitHub アカウントと AWS との接続を適宜新規追加した上で、先ほど作成した GitHub リポジトリを選択します。[ブランチ] と [ソースディレクトリ] は既定のままにします。

最後に [デプロイ設定] は、今回はお試しということで、「手動」を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/1139ff11-a7b2-e8e7-1155-0bab25b508bc.png)

この状態で [次へ] をクリックします。

### 構築を設定

すると [構築を設定] のページに移動します。[設定ファイル] の選択については、今回はお試しということもあり、ビルド関連の設定はこの AWS コンソール上で手入力して行ないたいと思いますので、「ここですべての設定を構成する」が既定で選択されたままにします。

そして [ランタイム] の選択ですが、ここで、今回のサンプルアプリケーションである Blazor Server の対象フレームワーク、「.NET 6」を選択します。

すると、[構築コマンド] と [開始コマンド] の入力欄が現れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/e20d6c75-63b0-f0b9-738e-1c2606eaa395.png)

#### 構築コマンド

まず [構築コマンド] には以下のコマンドを指定します。

```shell:[構築コマンド]
dotnet publish MyBlazorServerApp.csproj -c Release -o ./bin/publish
```

これはカレントフォルダにある `MyBlazorServerApp.csproj` プロジェクトファイルについて、発行 (publish) をリリース構成 (`-c Release`) で行なうものです。このとき、発行後の出力ファイルの保存先フォルダ (発行先フォルダ) を `./bin/publish` に指定しています (`-o` オプション)。発行先フォルダは必ずしもこのフォルダである必要はありませんが、bin フォルダ以下であれば万が一何か他のビルド作業へも影響がなさそうで、且つ、あまりフォルダ階層が深くならなさそう、ということで、自分は `./bin/publish` フォルダへ発行することとしました。

#### 開始コマンド

次に [開始コマンド] ですが、こちらは以下のコマンドを指定します。

```shell:[開始コマンド]
dotnet ./bin/publish/MyBlazorServerApp.dll --webroot ./bin/publish/wwwroot --urls http://+:8080
```

これは dotent CLI を使って、引数に指定したビルド済み .NET アセンブリファイルを実行するものですが、2 つのオプションを指定しています。

##### `--webroot` オプション

まずひとつめの `--webroot` オプションについてですが、これはこの .NET アプリケーション = Blazor Server アプリケーションにおいて静的コンテンツを配置してあるフォルダの位置を明示するものです。Blazor Server を含む ASP.NET Core Web アプリケーションにおける静的コンテンツの配置フォルダは、既定では、**カレントフォルダの下の** `wwwroot` フォルダ、となっています。しかし今回の構成では、カレントフォルダはプロジェクトがあるルート (`/`) フォルダなので、このままでは `./wwwroot` が静的コンテンツの配置フォルダとして使用されていまします。これを発行先フォルダの下の `wwwroot` フォルダを静的コンテンツの配置フォルダとして使ってもらう必要があります (そうしないと、Blazor の CSS 分離の仕組みによって生成される CSS ファイルが見つからなくなります)。そこで、`--webroot` オプションで静的コンテンツの配置フォルダを、発行先フォルダ以下の `wwwroot` フォルダであることを明示しています。

##### `--urls` オプション

続けてふたつめのオプション、`--urls` についてですが、これは、この Blazor Server アプリケーションの待ち受けアドレスとポート番号を指定するものです。このオプションを明示しない場合、Blazor Server を含む ASP.NET Core Web アプリケーションでは、既定で `http://localhost:5000` で待ち受けします。しかしこれでは、この Blazor Server アプリケーションが実行されているコンテナの外からの、AWS App Runner のリバースプロキシからの接続が受け入れられません (`localhost` でリッスンしているので)。また、AWS App Runner のリバースプロキシは、既定ではポート 8080 でコンテナ内の Web アプリケーションに接続しようとします。このポート番号は、次の設定項目 [ポート番号] で「5000」に変更することも可能ですが、前述のとおりそもそも `localhost` で待ち受けして外部からの接続を受け入れていないのが問題です。そこで、`--urls` オプションを使って、待ち受けする URL を `http://+:8080` と明示的に指定することで、AWS App Runner のリバースプロキシからの接続を、正しくこの Blazor Server アプリケーションが受信できるようにしました。

なお、Blazor Server を含む ASP.NET Core Web アプリケーションにおいて、待ち受け URL を構成する方法については過去に Qiita に投稿してます (下記リンク先)。ご参考までに。

https://qiita.com/jsakamoto/items/2c1a79a81e573885732e

以上で [次へ] をクリックします。

### サービスを設定

すると [サービス設定] のページに移動します。[サービス名] の欄には、自分で管理できるように適切なサービス名を入力します。[仮想 CPU] と [仮想メモリ] は、今回はとりあえず既定のまま「1 vCPU」と「2 GB」を選択したままで進めてみました。

[Auto Scaling] を適宜構成し、[ヘルスチェック] については、[プロトコル] の選択肢を「TCP」から「HTTP」に変更しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/a3ec50bf-8b5a-a043-b014-13a93dd04291.png)

以上で [次へ] をクリックします。

### 確認および作成

すると [確認および作成] のページに移動します。

設定内容を確認し、問題なければ [作成とデプロイ] をクリックして実行します。

すると、AWS App Runner が、以下の処理を開始します。

- 指定された GitHub リポジトリからソースコード一式をクローンし、
- [構築コマンド] に指定したコマンドを実行することで、プロジェクトをビルド・発行し、
- [開始コマンド] に指定したコマンドを実行することで、アプリケーションを実行開始

こうして最終的に、この AWS App Runner 上で稼働するサンプルの Blazor Server アプリケーションへインターネット経由でアクセスし、動作を確認することができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/9e4bcfa2-dace-8b1f-1964-c4e8d6df4754.png)


## AWS App Runner 上で稼働する Blazor Server とは WebSocket でつながるのか?

こうして動作確認できた AWS App Runner 上で稼働する Blazor Server アプリケーションですが、Web ブラウザの開発者ツールから、サーバーとの接続状況を確認したところ、WebSocket ではなくロングポーリングで接続されているようでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/58450/f59158ae-e06d-32c9-d791-c47e7f30861f.png)


下記リンク先の Issue を見る限り、本稿作成時点では、どうやら AWS App Runner では、WebSocket はサポートされていないっぽいです。

https://github.com/aws/apprunner-roadmap/issues/13

ということで、本稿作成時点では、AWS App Runner 上に配置した Blazor Server アプリケーションは、Long Polling でサーバーと接続するようです。Blazor Server におけるサーバー通信方法の違いについては、過去に Qiita に投稿してますので (下記リンク先)、ご参考までに。

https://qiita.com/jsakamoto/items/4f7bfbbb3e3ba2f31614

以上、AWS App Runner 上に Blazor Server アプリケーションを配置、稼働させてみることができました。

_Learn, Practice, Share! :)_