Azure Container Apps (ACA) に C# ASP.NET Core Webサービスをデプロイする (Docker Hub カスタムコンテナイメージ)
こんにちは、@studio_meowtoon です。今回は、Azure Container Apps 環境で C# ASP.NET Core Web アプリケーションをコンテナとして起動する方法を紹介します。
目的
Windows 11 の Linux でクラウド開発します。
こちらから記事の一覧がご覧いただけます。
実現すること
Microsoft Azure Container Apps (ACA) に C# ASP.NET Core Web アプリケーションのカスタムコンテナイメージをデプロイします。
DLL ファイル形式のアプリをコンテナとして起動
要素 | 概要 |
---|---|
terminal | ターミナル |
Azure | クラウド環境 |
Azure Container Apps | コンテナ実行環境 |
app-hello-aspnet-core | カスタムコンテナ |
dotnet | .NET 実行環境 |
kestrel | Web サーバー |
WebApp.dll | .NET アプリケーション |
この記事では、Docker Hub に公開するパブリックアクセス可能なカスタムコンテナイメージを使用しています。実際のシステム開発では、どのレジストリからコンテナイメージを取得するかは異なる場合がありますので、適宜ご確認ください。
技術トピック
Microsoft Azure Container Apps (ACA) とは?
こちらを展開してご覧いただけます。
Microsoft Azure Container Apps (ACA)
Azure 上で実行されるコンテナアプリケーションのプラットフォームです。
ACA は、Docker コンテナと Kubernetes クラスタの環境をサポートしており、開発者はコンテナイメージを作成して、Kubernetes リソースとしてデプロイすることができます。また、カスタムドメイン名をサポートしているため、自社のブランドを維持することができます。
メリット | 説明 |
---|---|
簡単なセットアップとデプロイ | ACA は、簡単なユーザーインターフェイスを備えており、数回のクリックでコンテナアプリケーションをセットアップしてデプロイすることができます。 |
スケーラビリティ | ACA は、自動的にスケーリングを行うことができます。アプリケーションに必要なリソースが増加した場合、ACA は自動的に必要なリソースを追加して処理を分散します。 |
セキュリティ | ACA は、コンテナアプリケーションを実行する際に必要なセキュリティ機能を提供しています。例えば Azure Active Directory との統合や、コンテナレベルでのアクセス制御などがあります。 |
コスト効率 | ACA は、必要なときに必要なリソースを追加するため、無駄なリソースの使用を最小限に抑えることができます。また、必要なリソースに対してのみ支払いを行うため、コスト効率的に利用することができます。 |
開発環境
- Windows 11 Home 22H2 を使用しています。
WSL の Ubuntu を操作していきますので macOS の方も参考にして頂けます。
WSL (Microsoft Store アプリ版) ※ こちらの関連記事からインストール方法をご確認いただけます
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
Ubuntu ※ こちらの関連記事からインストール方法をご確認いただけます
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 22.04.1 LTS
Release: 22.04
.NET SDK ※ こちらの関連記事からインストール方法をご確認いただけます
$ dotnet --list-sdks
7.0.202 [/usr/share/dotnet/sdk]
$ dotnet --version
7.0.202
Docker ※ こちらの関連記事からインストール方法をご確認いただけます
$ docker --version
Docker version 23.0.1, build a5ee5b1
Azure CLI ※ こちらの関連記事からインストール方法をご確認いただけます
$ az --version
azure-cli 2.45.0
core 2.45.0
telemetry 1.0.8
この記事では基本的に Ubuntu のターミナルで操作を行います。Vim を使用してコピペする方法を初めて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
作成する Web アプリケーションの仕様
No | エンドポイント | HTTPメソッド | MIME タイプ |
---|---|---|---|
1 | /api/data | GET | application/json |
Hello World を表示する手順
C# ASP.NET Core Web サービスの作成
こちらの関連記事で手順がご確認いただけます。
ここまでの手順で、ローカル環境の Ubuntu にアプリのカスタムコンテナイメージをビルドすることができました。
プロジェクトフォルダに移動
プロジェクトフォルダに移動します。
※ ~/tmp/WebApp をプロジェクトフォルダとします。
$ cd ~/tmp/WebApp
コンテナイメージの確認
Docker デーモンを起動します。
$ sudo service docker start
* Starting Docker: docker [ OK ]
Docker 環境をお持ちでない場合は、以下の関連記事から Docker Engine のインストール手順をご確認いただけます。
コンテナイメージを確認します。
$ docker images | grep app-hello-aspnet-core
app-hello-aspnet-core latest 0d756b19ebac 25 minutes ago 212MB
Docker Hub にコンテナイメージを登録
Docker Hub のアカウントを作成します。
Docker Hub にログインします。
$ docker login
Login Succeeded
コンテナイメージにタグを付けます。
ここで $USER という埋め込み変数は、Ubuntu のシェル変数 USER のことです。つまり、カスタムコンテナイメージを Docker Hub にプッシュする際に指定するアカウント名と、Ubuntu のユーザー名を同じにすると、イメージの取り扱いが簡単になります。ただし、この方法は検証用途に限定されます。
$ docker tag app-hello-aspnet-core:latest \
$USER/app-hello-aspnet-core:latest
Docker Hub にコンテナイメージをプュシュします。
$ docker push $USER/app-hello-aspnet-core:latest
ここまでの作業で、Docker Hub に $USER/app-hello-aspnet-core:latest としてカスタムコンテナイメージをプッシュすることができました。
シェル変数の作成
シェル変数として、Ubuntu に以下の値を作成します。状況により、コンテナ アプリの名前を変える必要があります。
location_name=japaneast
resource_group_name=rg-hello
containerapp_env_name=cae-hello
containerapp_name=ca-hello-aspnet-core
container_image_name=app-hello-aspnet-core:latest
Azure 環境にサインイン
こちらの関連記事で手順がご確認いただけます。
Azure CLI でログインします。
$ az login
Azure 環境
リソースグループ
リソースグループを作成します。
$ az group create \
--name $resource_group_name \
--location $location_name
コンテナ アプリ環境
拡張機能をインストールします。
※ 初回のみ必要となります。
手順を表示します。
拡張機能
拡張機能をインストールします。
$ az extension add --name containerapp --upgrade
Microsoft.App 名前空間を登録します。
$ az provider register --namespace Microsoft.App
Microsoft.OperationalInsights プロバイダーを登録します。
$ az provider register --namespace Microsoft.OperationalInsights
コンテナ アプリ環境を作成します。
※ Kubernetes 基盤の環境がベースとなっているので少し時間がかかります。
$ az containerapp env create \
--resource-group $resource_group_name \
--name $containerapp_env_name \
--location $location_name
コンテナ アプリ
コンテナ アプリの作成とデプロイを行います。
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。
$ az containerapp create \
--resource-group $resource_group_name \
--environment $containerapp_env_name \
--name $containerapp_name \
--image $USER/$container_image_name \
--target-port 80 \
--ingress 'external' \
--min-replicas 0
--min-replicas 0: と設定することにより、アクセスが300秒間ない場合にアプリケーションがスケールゼロ状態に移行します。
コンテナ アプリを削除する場合は以下のコマンドを実行します。
$ az containerapp delete \
--resource-group $resource_group_name \
--name $containerapp_name
コンテナ アプリの FQDN をシェル変数 containerapp_fqdn として取得します。
$ containerapp_fqdn=$(az containerapp show \
--resource-group $resource_group_name \
--name $containerapp_name \
--query 'properties.configuration.ingress.fqdn' \
--output tsv)
コンテナ アプリの FQDN を確認します。
$ set | grep containerapp_fqdn
containerapp_fqdn=ca-hello-aspnet-core.yellowcliff-d8392fa5.japaneast.awsomecontainerapps.io
Azure Portal の確認
ここまでの作業で、Azure Container Apps にコンテナ アプリをデプロイすることができました。
コンテナ動作の確認
ターミナルから curl コマンドで確認します。
$ curl https://$containerapp_fqdn/api/data -w '\ntime_total: %{time_total}s\n'
出力(※ time_total は省略)
{"message":"Hello World!"}
詳細を表示します。
$ curl -v https://$containerapp_fqdn/api/data -w "\n"
* Trying xx.xx.xx.xx:443...
* Connected to ca-hello-aspnet-core.thankfulstone-5dxxxx03.japaneast.azurecontainerapps.io (xx.xx.xx.xx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: /etc/ssl/certs/ca-certificates.crt
* CApath: /etc/ssl/certs
* TLSv1.0 (OUT), TLS header, Certificate Status (22):
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS header, Finished (20):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS header, Finished (20):
* TLSv1.2 (IN), TLS header, Certificate Status (22):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-CHACHA20-POLY1305
* ALPN, server accepted to use h2
* Server certificate:
* subject: C=US; ST=WA; L=Redmond; O=Microsoft Corporation; CN=thankfulstone-5dxxxx03.japaneast.azurecontainerapps.io
* start date: Mar 24 02:56:09 2023 GMT
* expire date: Mar 18 02:56:09 2024 GMT
* subjectAltName: host "ca-hello-aspnet-core.thankfulstone-5dxxxx03.japaneast.azurecontainerapps.io" matched cert's "*.thankfulstone-5dxxxx03.japaneast.azurecontainerapps.io"
* issuer: C=US; O=Microsoft Corporation; CN=Microsoft Azure TLS Issuing CA 01
* SSL certificate verify ok.
* Using HTTP2, server supports multiplexing
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* Using Stream ID: 1 (easy handle 0x55b45d69de90)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET /api/data HTTP/2
> Host: ca-hello-aspnet-core.thankfulstone-5dxxxx03.japaneast.azurecontainerapps.io
> user-agent: curl/7.81.0
> accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 200
< content-type: application/json
< date: Fri, 24 Mar 2023 23:08:38 GMT
< server: Kestrel
<
* Connection #0 to host ca-hello-aspnet-core.thankfulstone-5dxxxx03.japaneast.azurecontainerapps.io left intact
{"message":"Hello World!"}
Azure Container Apps 自体が SSL/TLS 対応および HTTP/2 プロトコルをサポートしています。
ここまでの手順で、ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。
コンテナに接続
コンテナ アプリに接続します。
$ az containerapp exec \
--resource-group $resource_group_name \
--name $containerapp_name
コンテナに接続後にディレクトリを確認します。
※ コンテナから出るときは ctrl + D を押します。
# pwd
/App
# ls -lah
total 240K
drwxr-xr-x 1 root root 4.0K Aug 3 01:10 .
drwxr-xr-x 1 root root 4.0K Aug 3 02:17 ..
-rwxr-xr-x 1 root root 177K Aug 3 01:10 WebApp
-rw-r--r-- 1 root root 388 Aug 3 01:10 WebApp.deps.json
-rw-r--r-- 1 root root 9.0K Aug 3 01:10 WebApp.dll
-rw-r--r-- 1 root root 20K Aug 3 01:10 WebApp.pdb
-rw-r--r-- 1 root root 469 Aug 3 01:10 WebApp.runtimeconfig.json
-rw-r--r-- 1 root root 410 Aug 3 00:16 appsettings.Development.json
-rw-r--r-- 1 root root 434 Aug 3 00:16 appsettings.json
-rw-r--r-- 1 root root 482 Aug 3 01:10 web.config
top コマンドで状況を確認します。
# apt update
# apt install procps
# top
top - 02:18:38 up 6:03, 0 users, load average: 0.17, 0.26, 0.26
Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 1.8 us, 0.8 sy, 0.0 ni, 97.3 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
MiB Mem : 15990.8 total, 4957.6 free, 2071.8 used, 8961.4 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 13552.9 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 7104376 73784 60572 S 0.3 0.5 0:00.46 dotnet
21 root 20 0 2480 516 448 S 0.0 0.0 0:00.00 sh
363 root 20 0 6996 3352 2868 R 0.0 0.0 0:00.00 top
top コマンドで cpu を表示した状況です。
top - 02:18:52 up 6:03, 0 users, load average: 0.13, 0.25, 0.25
Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu0 : 2.0 us, 1.0 sy, 0.0 ni, 96.9 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 3.3 us, 0.7 sy, 0.0 ni, 95.7 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
%Cpu2 : 2.3 us, 1.0 sy, 0.0 ni, 96.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 1.7 us, 0.7 sy, 0.0 ni, 97.6 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 15990.8 total, 4957.1 free, 2071.8 used, 8961.9 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 13553.0 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 7178120 73816 60576 S 0.0 0.5 0:00.47 dotnet
21 root 20 0 2480 516 448 S 0.0 0.0 0:00.00 sh
363 root 20 0 6996 3352 2868 R 0.0 0.0 0:00.00 top
コンテナの情報を表示してみます。
# cat /etc/*-release
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
このコンテナは Debian GNU/Linux をベースに作成されています。つまり、Debian GNU/Linux と同じように扱うことができます。
パフォーマンスの計測
コンテナ 環境
項目 | バージョン |
---|---|
Base Image | Debian GNU/Linux 11 |
dotnet | 7.0 |
ASP.NET Core | 7.0 |
コンテナ リソースの割り当て
項目 | 設定値 |
---|---|
CPU コアの数 | 0.5 |
メモリ サイズ(Gi) | 1Gi |
リクエスト処理完了までの所要時間
No | 状況 | リクエスト所要時間(秒) |
---|---|---|
1 | デプロイ直後 | 0.346665秒 |
2 | 連続して2回目 | 0.197049秒 |
3 | さらに3回目 | 0.191124秒 |
4 | スケールゼロ回復直後 | 7.104071秒 |
5 | 連続して2回目 | 0.202285秒 |
6 | さらに3回目 | 0.196141秒 |
ログ ストリーム:起動時間を表示するログ
※該当するログ情報なし
状況 | アプリ起動時間(秒) |
---|---|
デプロイ直後 | ---秒 |
スケールゼロ回復直後 | ---秒 |
メトリック:CPU使用率
状況 | CPU使用率 |
---|---|
デプロイ後:ピーク値 | 0.00707コア |
スケールゼロ回復後:ピーク値 | 0.01コア |
メトリック:メモリ使用量
状況 | メモリ使用量 |
---|---|
デプロイ後:ピーク値 | 28.9MB |
スケールゼロ回復後:ピーク値 | 26.6MB |
アプリケーションがスケールゼロ状態から再びアクティブになった後、リクエストを処理するまでにかなり時間がかかる状況がわかります。ただしスケールゼロ状態は、--min-replicas 1: と設定することにより回避可能です。
まとめ
Azure Container Apps 環境で、Dockerfile からビルドした C# ASP.NET Core Web サービスのカスタムコンテナイメージを起動することができました。
.NET SDK、Docker、Azure CLI を使って、ASP.NET Core アプリの開発からコンテナイメージの作成、Azure 環境へのデプロイまで、すべてをターミナルから行うことができます。このように、クラウドでのシステム開発に必要なスキルや理解を深めることができます。初めての人でも簡単に手順を追うことができるので、ぜひ挑戦してみてください。
どうでしたか? 検証目的として、WSL Ubuntu で、C# ASP.NET Core Web アプリケーションを Azure Container Apps 環境でコンテナとして手軽に起動することができます。ぜひお試しください。今後も Azure の開発環境などを紹介していきますので、ぜひお楽しみにしてください。
推奨コンテンツ
関連記事
Java Spring Boot