Azure Container Apps (ACA) に Spring Boot カスタムコンテナイメージをデプロイする:GraalVM ネイティブイメージ
こんにちは、@studio_meowtoon です。今回は、Azure Container Apps 環境で、GraalVM ネイティブイメージ Spring Boot Web アプリケーションをコンテナとして起動する方法を紹介します。
目的
Windows 11 の Linux でクラウド開発します。
こちらから記事の一覧がご覧いただけます。
実現すること
Microsoft Azure Container Apps (ACA) に GraalVM ネイティブイメージ Spring Boot Web アプリケーションのカスタムコンテナイメージをデプロイします。
ネイティブイメージ形式のアプリをコンテナとして起動
要素 | 概要 |
---|---|
terminal | ターミナル |
Azure | クラウド環境 |
Azure Container Apps | コンテナ実行環境 |
app-hello-spring-boot-native | カスタムコンテナ |
app | ネイティブイメージ アプリケーション |
tomcat | Web サーバー |
この記事では、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
Java JDK ※ こちらの関連記事からインストール方法をご確認いただけます
$ java -version
openjdk version "17.0.6" 2023-01-17
OpenJDK Runtime Environment GraalVM CE 22.3.1 (build 17.0.6+10-jvmci-22.3-b13)
OpenJDK 64-Bit Server VM GraalVM CE 22.3.1 (build 17.0.6+10-jvmci-22.3-b13, mixed mode, sharing)
Maven ※ こちらの関連記事からインストール方法をご確認いただけます
$ mvn -version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.18, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
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 を表示する手順
Spring Boot Web サービスの作成
こちらの関連記事で手順がご確認いただけます。
ここまでの手順で、ローカル環境の Docker にアプリのネイティブイメージのカスタムコンテナイメージをビルドすることができました。
プロジェクトフォルダに移動
プロジェクトフォルダに移動します。
※ ~/tmp/hello-spring-boot をプロジェクトフォルダとします。
$ cd ~/tmp/hello-spring-boot
コンテナイメージの確認
Docker デーモンを起動します。
$ sudo service docker start
* Starting Docker: docker [ OK ]
コンテナイメージを確認します。
$ docker images | grep app-hello-spring-boot-native
app-hello-spring-boot-native latest f0794df4d28c 23 minutes ago 149MB
Docker Hub にコンテナイメージを登録
Docker Hub にログインします。
$ docker login
Login Succeeded
コンテナイメージにタグを付けます。
ここで $USER という埋め込み変数は、Ubuntu のシェル変数 USER のことです。つまり、カスタムコンテナイメージを Docker Hub にプッシュする際に指定するアカウント名と、Ubuntu のユーザー名を同じにすると、イメージの取り扱いが簡単になります。ただし、この方法は検証用途に限定されます。
$ docker tag app-hello-spring-boot-native:latest \
$USER/app-hello-spring-boot-native:latest
Docker Hub にコンテナイメージをプュシュします。
$ docker push $USER/app-hello-spring-boot-native:latest
ここまでの手順で、Docker Hub に $USER/app-hello-spring-boot-native:latest というカスタムコンテナイメージをプッシュすることができました。
シェル変数の作成
シェル変数として、Ubuntu に以下の値を作成します。状況により、コンテナ アプリの名前を変える必要があります。
location_name=japaneast
resource_group_name=rg-hello
containerapp_env_name=cae-hello
containerapp_name=ca-hello-spring-boot-native
container_image_name=app-hello-spring-boot-native:latest
Azure 環境にサインイン
こちらの関連記事の続きから手順を説明する記事となります。
Azure CLI でログインします。
$ az login
Azure 環境
リソースグループ
リソースグループを作成します。
$ az group create \
--name $resource_group_name \
--location $location_name
コンテナ アプリ環境
コンテナ アプリ環境を作成します。
※ Kubernetes 基盤の環境がベースとなっているので少し時間がかかります。
$ az containerapp env create \
--resource-group $resource_group_name \
--name $containerapp_env_name \
--location $location_name
コンテナ アプリ
コンテナ アプリの作成とデプロイを行います。
$ az containerapp create \
--resource-group $resource_group_name \
--environment $containerapp_env_name \
--name $containerapp_name \
--image $USER/$container_image_name \
--target-port 8080 \
--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-spring-boot-native.wonderfuldune-033c35fb.japaneast.awesomecontainerapps.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!"}
ここまでの作業で、ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。
コンテナに接続
コンテナ アプリに接続
$ az containerapp exec \
--resource-group $resource_group_name \
--name $containerapp_name
コンテナに接続後にディレクトリを確認します。
※ コンテナから出るときは ctrl + D を押します。
# pwd
/app
# ls -lah
total 67M
drwxr-xr-x 1 root root 4.0K Aug 2 09:18 .
drwxr-xr-x 1 root root 4.0K Aug 2 11:03 ..
-rwxr-xr-x 1 root root 67M Aug 2 09:16 app
top コマンドで状況を確認します。
top - 11:04:32 up 18:34, 0 users, load average: 0.10, 0.18, 0.29
Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu(s): 2.4 us, 1.0 sy, 0.0 ni, 96.5 id, 0.0 wa, 0.0 hi, 0.1 si, 0.0 st
MiB Mem : 15990.8 total, 4189.2 free, 2167.2 used, 9634.4 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 13467.9 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 1396004 94288 48104 S 0.0 0.6 0:00.06 app
24 root 20 0 2888 956 864 S 0.0 0.0 0:00.00 sh
31 root 20 0 7316 3492 2928 R 0.0 0.0 0:00.00 top
top コマンドで cpu を表示した状況です。
top - 11:04:45 up 18:35, 0 users, load average: 0.09, 0.17, 0.28
Tasks: 3 total, 1 running, 2 sleeping, 0 stopped, 0 zombie
%Cpu0 : 2.4 us, 0.3 sy, 0.0 ni, 97.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 : 0.7 us, 0.3 sy, 0.0 ni, 99.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 1.0 us, 0.0 sy, 0.0 ni, 99.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 2.0 us, 0.3 sy, 0.0 ni, 97.7 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 15990.8 total, 4192.7 free, 2163.4 used, 9634.7 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 13471.7 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 1396004 94288 48104 S 0.0 0.6 0:00.06 app
24 root 20 0 2888 956 864 S 0.0 0.0 0:00.00 sh
31 root 20 0 7316 3492 2928 R 0.0 0.0 0:00.00 top
Spring Boot として動作していますが、java コマンドが起動していないことが確認できます。つまり JVM を必要としません。
コンテナの情報を表示してみます。
# cat /etc/*-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=22.04
DISTRIB_CODENAME=jammy
DISTRIB_DESCRIPTION="Ubuntu 22.04.2 LTS"
PRETTY_NAME="Ubuntu 22.04.2 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.2 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
このコンテナは Ubuntu をベースに作成されています。つまり、Ubuntu と同じように扱うことができます。
パフォーマンスの計測
コンテナ 環境
項目 | バージョン |
---|---|
Base Image | Ubuntu 22.04.2 LTS |
Spring Boot | v3.0.4 |
コンテナ リソースの割り当て
項目 | 設定値 |
---|---|
CPU コアの数 | 0.5 |
メモリ サイズ(Gi) | 1Gi |
リクエスト処理完了までの所要時間
No | 状況 | リクエスト所要時間(秒) |
---|---|---|
1 | デプロイ直後 | 0.233591秒 |
2 | 連続して2回目 | 0.175264秒 |
3 | さらに3回目 | 0.173258秒 |
4 | スケールゼロ回復直後 | 7.049757秒 |
5 | 連続して2回目 | 0.209536秒 |
6 | さらに3回目 | 0.189759秒 |
ログ ストリーム:起動時間を表示するログ
状況 | アプリ起動時間(秒) |
---|---|
デプロイ直後 | 0.042秒 |
スケールゼロ回復直後 | 0.039秒 |
2023-08-02T10:44:27.514912040Z 2023-08-02T10:44:27.514Z INFO 1 --- [ main] com.example.springboot.Application : Started Application in 0.042 seconds (process running for 0.045)
2023-08-02T10:55:00.896887847Z 2023-08-02T10:55:00.896Z INFO 1 --- [ main] com.example.springboot.Application : Started Application in 0.039 seconds (process running for 0.042)
メトリック:CPU使用率
状況 | CPU使用率 |
---|---|
デプロイ後:ピーク値 | 0.00101コア |
スケールゼロ回復後:ピーク値 | 0.00095コア |
メトリック:メモリ使用量
状況 | メモリ使用量 |
---|---|
デプロイ後:ピーク値 | 54.7MB |
スケールゼロ回復後:ピーク値 | 56.1MB |
アプリケーションがスケールゼロ状態から再びアクティブになった後、リクエストを処理するまでにかなり時間がかかる状況がわかります。ただしスケールゼロ状態は、--min-replicas 1: と設定することにより回避可能です。
まとめ
Azure Container Apps 環境で、Dockerfile からビルドした GraalVM ネイティブイメージ Spring Boot Web サービスのカスタムコンテナイメージを起動することができました。
Maven、Docker、Azure CLI を使って、Spring Boot アプリの開発からコンテナイメージの作成、Azure 環境へのデプロイまで、すべてをターミナルから行うことができます。このように、クラウドでのシステム開発に必要なスキルや理解を深めることができます。初めての人でも簡単に手順を追うことができるので、ぜひ挑戦してみてください。
どうでしたか? 検証目的として、Azure Container Apps 環境で、GraalVM ネイティブイメージ Spring Boot Web アプリケーションをコンテナとして手軽に起動することができます。ぜひお試しください。今後も Azure の開発環境などを紹介していきますので、ぜひお楽しみにしてください。
関連記事
通常のカスタムコンテナイメージのデプロイと比較してみましょう!