Azure App Service に Spring Boot Webサービスをデプロイする (Docker Hub カスタムコンテナイメージ)

# Azure App Service に Spring Boot Webサービスをデプロイする (Docker Hub カスタムコンテナイメージ)

こんにちは、@studio_meowtoon です。今回は、Azure App Service 環境で Spring Boot Web アプリケーションをコンテナとして起動する方法を紹介します。
![spring-boot_on_azure-app-service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/ee889e17-aa44-6f41-bf48-ee2242c1d115.png)

## 目的

Windows 11 の Linux でクラウド開発します。

こちらから記事の一覧がご覧いただけます。

https://qiita.com/studio_meowtoon/items/6119ab05d8b13527efd8 

## 実現すること

Microsoft Azure App Service に Spring Boot Web アプリケーションのカスタムコンテナイメージをデプロイします。  

:::note alert
この記事では、**Docker Hub** に公開する**パブリックアクセス可能なカスタムコンテナイメージ**を使用しています。実際のシステム開発では、どのレジストリからコンテナイメージを取得するかは異なる場合がありますので、適宜ご確認ください。

また、Azure には完全にマネージドされたレジストリサービスである **Azure Container Registry** が利用できます。Azure CLI を使用しての操作方法もありますので、別の機会にご紹介したいと思います。
:::

## 技術トピック

### Microsoft Azure App Service とは？  

<details>
<summary>こちらを展開してご覧いただけます。</summary>

### [Microsoft Azure App Service](https://learn.microsoft.com/ja-jp/azure/app-service/overview)

:::note info
Azure 上で実行されるコンテナアプリケーションのプラットフォームです。  

Microsoft Azure App Service は、Microsoft Azure の PaaS (Platform as a Service) サービスの一つで、Web アプリケーションやモバイルアプリケーション、API アプリケーションのホスティングに特化したサービスです。 

|特徴とメリット|説明|
|:--|:--|
|簡単なデプロイ|Azure App Service は、Azure Portal や Azure CLI、Azure DevOps などのツールを使って、Web アプリケーションを簡単にデプロイできます。また、多数のプログラミング言語やフレームワークに対応しており、柔軟な開発が可能です。|
|スケーラビリティ|Azure App Service は、自動スケーリングや手動スケーリングをサポートしており、アプリケーションの負荷に応じて柔軟にスケールできます。|
|高可用性|Azure App Service は、グローバルな負荷分散やフェイルオーバー機能を備えており、高い可用性を実現できます。|
|統合|Azure App Service は、Azure の他のサービスとシームレスに統合できます。例えば、Azure SQL Database や Azure Storage などのストレージサービスと連携して、アプリケーションのデータ管理を容易にします。|
|セキュリティ|Azure App Service は、ネットワークセキュリティグループ (NSG) や Web アプリケーションファイアウォール (WAF) などのセキュリティ機能を提供しており、アプリケーションのセキュリティを高めることができます。|

これらの特徴とメリットにより、Azure App Service は、開発者や企業にとって、高速かつ柔軟な Web アプリケーションの開発とデプロイを支援するプラットフォームとして利用されています。
:::

</details>

## 開発環境

+ Windows 11 Home 22H2 を使用しています。  

:::note info
[WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作していきますので macOS の方も参考にして頂けます。  
:::

<details>

WSL (Microsoft Store アプリ版) [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/2aaa6579cb8e4fa1d874)

```sh
> wsl --version
WSL バージョン: 1.0.3.0
カーネル バージョン: 5.15.79.1
WSLg バージョン: 1.0.47
```

Ubuntu [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/2aaa6579cb8e4fa1d874)

```sh
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 22.04.1 LTS
Release:        22.04
```

Java JDK [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/4d11e94a2389758759cd)

```sh
$ java -version
openjdk version "11.0.18" 2023-01-17
OpenJDK Runtime Environment (build 11.0.18+10-post-Ubuntu-0ubuntu122.04)
OpenJDK 64-Bit Server VM (build 11.0.18+10-post-Ubuntu-0ubuntu122.04, mixed mode, sharing)
```

Maven [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/f4cdc4039158153365fb)

```sh
$ 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 [※ こちらの関連記事からインストール方法をご確認いただけます](https://qiita.com/studio_meowtoon/items/3bceee25ac67cc73ebbe)

```sh
$ docker --version
Docker version 23.0.1, build a5ee5b1
```

</details>

:::note warn
この記事では基本的に **Ubuntu のターミナルで操作**を行います。**Vim を使用してコピペする方法**を初めて学ぶ人のために、以下の記事で手順を紹介しています。ぜひ挑戦してみてください。
:::

https://qiita.com/studio_meowtoon/items/7771ad48676926e41463

## Hello World を表示する手順

### Spring Boot Web サービスの作成

こちらの関連記事の続きから手順を説明する記事となります。

https://qiita.com/studio_meowtoon/items/37ac0082a3228e4de570

### Spring Boot アプリのプロジェクトフォルダに移動

プロジェクトフォルダに移動します。  
※ ~/tmp/hello-spring-boot をプロジェクトフォルダとします。

```sh
$ cd ~/tmp/hello-spring-boot
```

### コンテナイメージの確認

こちらの関連記事の続きから手順を説明する記事となります。

https://qiita.com/studio_meowtoon/items/9c07e20b4124d8c5f972

Docker デーモンを起動します。

```sh
$ sudo service docker start
 * Starting Docker: docker      [ OK ]
```

コンテナイメージを確認します。

```sh
$ docker images | grep app-hello-spring-boot
app-hello-spring-boot   latest    39115028afa6   12 seconds ago   390MB
```

### Docker Hub にコンテナイメージを登録  

Docker Hub のアカウントを作成します。  

https://hub.docker.com/signup

:::note warn
Docker Hub は、コンテナの共有、保存、および管理のためのクラウドベースのレジストリです。Docker Hub には、コミュニティによって作成された公式およびコミュニティによるイメージが格納されています。また、**ユーザーがカスタムコンテナイメージをアップロードおよび共有する**こともできます。
:::

Docker Hub にログインします。  

```sh
$ docker login
Login Succeeded
```

コンテナイメージにタグを付けます。
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh
$ docker tag app-hello-spring-boot $USER/app-hello-spring-boot:latest
```

<details>
<summary>説明を開きます。</summary>

:::note info
**docker tag** コマンドは、ローカルに保存されているコンテナイメージに、指定したタグを付けることで、コンテナイメージをリネームすることができます。  

この例では、**app-hello-spring-boot** という名前の**コンテナイメージ**に、**user/app-hello-spring-boot:latest** という**タグ**を付けています。ここで user は、Docker Hub 上のユーザー名を表します。タグには、コロン : 以降にバージョンなどの情報を含めることができますが、ここでは latest を指定しているため、最新バージョンを表しています。
:::

</details>

Docker Hub にコンテナイメージをプュシュします。

```sh
$ docker push $USER/app-hello-spring-boot:latest
```

<details>
<summary>説明を開きます。</summary>

:::note info
**docker push** コマンドは、コンテナイメージを Docker Hub のリポジトリにプッシュするために使用されます。user/app-hello-spring-boot はプッシュするイメージの名前とタグを指定し、latest はイメージのバージョンを指定しています。  

これにより、Docker Hub 上に **user** というユーザー名の**リポジトリ**が作成され、その中に **app-hello-spring-boot** という名前の**コンテナイメージ**がアップロードされます。  
:::

</details>

ここまでで、Docker Hub に $USER/app-hello-spring-boot:latest としてカスタムコンテナイメージが公開出来ました。  

### Azure 環境にサインイン

こちらの関連記事の続きから手順を説明する記事となります。 

https://qiita.com/studio_meowtoon/items/9721041f9e6e3e987cf0

Azure CLI でログインします。  

```sh
$ az login
```

### Azure 環境

#### リソースグループ

リソースグループを作成します。

```sh:Microsoft.Resources/resourceGroups
$ az group create \
    --name rg-hello \
    --location japaneast
```

<details>
<summary>説明を開きます。</summary>

:::note info
このコマンドは、Azure CLI を使用して Azure のリソースグループを作成しています。

|コマンド|内容|
|:--|:--|
|az group create|Azure のリソースグループを作成するためのコマンドです。|

|オプション|値|内容|
|:--|:--|:--|
|--name|rg-hello|リソースグループの名前を指定します。|
|--location|japaneast|リソースグループを作成する場所を **japaneast** に指定しています。 **japaneast** は Azure の日本東部地域を指します。|
:::

</details>

#### App Service プラン

App Service プランを作成します。

```sh:Microsoft.Web/serverfarms
$ az appservice plan create \
    --resource-group rg-hello \
    --name asp-hello \
    --sku Free \
    --is-linux
```

<details>
<summary>説明を開きます。</summary>

:::note info
このコマンドは、App Service プランを作成しています。

|コマンド|内容|
|:--|:--|
|az appservice plan create|App Service プランを作成するためのコマンドです。|

|オプション|値|内容|
|:--|:--|:--|
|--resource-group|rg-hello|App Service プランを作成するリソースグループの名前を指定します。|
|--name|asp-hello|App Service プランの名前を指定します。|
|--sku|Free|App Service プランのサービスレベルを指定します。この場合、Free プランを選択しています。|
|--is-linux|--|App Service プランが Linux ベースのホストであるかどうかを指定します。|
:::

</details>

App Service プランを一覧表示してみます。

```sh
$ az appservice plan list
```

:::note warn
App Service プランを削除する場合場合は以下のコマンドです。  
:::

```sh
$ az appservice plan delete -n <plan> -g <group>
```

#### App Service Web アプリ

Web アプリの作成とデプロイをを行います。  
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh:Microsoft.Web/sites
$ az webapp create \
    --resource-group rg-hello \
    --plan asp-hello \
    --name app-hello-spring-boot \
    --deployment-container-image-name $USER/app-hello-spring-boot:latest
```

<details>
<summary>説明を開きます。</summary>

:::note info
このコマンドは、App Service Web アプリを作成しています。

|コマンド|内容|
|:--|:--|
|az webapp create|App Service Web アプリを作成するためのコマンドです。|

|オプション|値|内容|
|:--|:--|:--|
|--resource-group|rg-hello|App Service Web アプリを作成するリソースグループの名前を指定します。|
|--plan|asp-hello|App Service Web アプリを作成する、App Service プランの名前を指定します。|
|--name|app-hello-spring-boot|App Service Web アプリの名前を指定します。|
|--deployment-container-image-name|$USER/app-hello-spring-boot:latest|Web アプリとしてデプロイするコンテナイメージを指定します。|

:::
</details>

Web アプリの設定を構成します。  
※ App Service Web アプリはデフォルトで 80 番ポートをリッスンする仕様です。  

```sh
$ az webapp config appsettings set \
    --resource-group rg-hello \
    --name app-hello-spring-boot \
    --settings WEBSITES_PORT=8080
```

<details>
<summary>説明を開きます。</summary>

:::note info
このコマンドは、App Service Web アプリの構成設定を変更しています。

|コマンド|内容|
|:--|:--|
|az webapp config appsettings set|App Service Web アプリの構成設定を変更するためのコマンドです。|

|オプション|値|内容|
|:--|:--|:--|
|--resource-group|rg-hello|App Service Web アプリを含むリソースグループの名前を指定します。|
|--name|app-hello-spring-boot|App Service Web アプリの名前を指定します。|
|--settings|WEBSITES_PORT=8080|App Service Web アプリがポート8080 で実行されるように設定します。|
:::

</details>

:::note warn
App Service Web アプリを削除する場合は以下のコマンドです。
:::

```sh
$ az webapp delete -n <name> -g <group>
```

### Web アプリ動作の確認

以下のコマンドを実行すると、WEBブラウザーが立ち上がります。  

```sh
$ az webapp browse \
    --resource-group rg-hello \
    --name app-hello-spring-boot
```

:::note warn
立ち上がりに少し時間が掛かりますがページが表示されます。 しかし表示されたページ "/" にはコンテンツを設定していません。
:::

WEBブラウザには以下のように表示されます。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/816fe3e4-eceb-0b3d-e63e-1acbc1d3c44c.png)
改めてWEBブラウザで確認します。    
※ URLは環境で読み替えて下さい。  

```sh
https://app-hello-spring-boot.awesomewebsites.net/api/data
```

WEBブラウザに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。  

※ 別ターミナルから curl コマンドで確認してみます。  

```
$ curl -v https://app-hello-spring-boot.awesomewebsites.net/api/data
```

<details>
<summary>詳細を表示します。</summary>

```
$ curl -v https://app-hello-spring-boot.awesomewebsites.net/api/data
*   Trying xx.xx.xx.xx:443...
* Connected to app-hello-spring-boot.awesomewebsites.net (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 handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* 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-AES256-GCM-SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=WA; L=Redmond; O=Microsoft Corporation; CN=*.awesomewebsites.net
*  start date: Dec 27 21:12:39 2022 GMT
*  expire date: Dec 22 21:12:39 2023 GMT
*  subjectAltName: host "app-hello-spring-boot.awesomewebsites.net" matched cert's "*.awesomewebsites.net"
*  issuer: C=US; O=Microsoft Corporation; CN=Microsoft Azure TLS Issuing CA 05
*  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 0x556a1919fe90)
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET /api/data HTTP/2
> Host: app-hello-spring-boot.awesomewebsites.net
> 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):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* TLSv1.2 (IN), TLS header, Supplemental data (23):
< HTTP/2 200
< content-type: application/json
< date: Wed, 08 Mar 2023 02:56:49 GMT
< set-cookie: ARRAffinity=f7e8112d174b035dedc0e95aa90dd578d821ba1ae7596ea4277e4837d982995e;Path=/;HttpOnly;Secure;Domain=app-hello-spring-boot.awesomewebsites.net
< set-cookie: ARRAffinitySameSite=f7e8112d174b035dedc0e95aa90dd578d821ba1ae7596ea4277e4837d982995e;Path=/;HttpOnly;SameSite=None;Secure;Domain=app-hello-spring-boot.awesomewebsites.net
<
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Connection #0 to host app-hello-spring-boot.awesomewebsites.net left intact
{"message":"Hello World!"}
```

</details>

ターミナルに {"message":"Hello World!"} と表示され、JSON データを取得することが出来ました。  

:::note info 
Azure App Service 自体が SSL/TLS 対応および HTTP/2 プロトコルをサポートしています。
:::

### コンテナに接続

:::note alert
Azure App Service Web アプリを**カスタムコンテナイメージ**から作成した場合、デフォルトの設定では**コンテナに接続できません**。以下の記事でコンテナに接続する方法を紹介しています。
:::

https://qiita.com/studio_meowtoon/items/9ebbcc362d1e93bd2ec1

## まとめ

Azure App Service 環境で、Dockerfile からビルドした Spring Boot Web サービスのカスタムコンテナイメージを起動することができました。

:::note warn
**Maven**、**Docker**、**Azure CLI** を使って、Spring Boot アプリの開発からコンテナイメージの作成、Azure 環境へのデプロイまで、**すべてをターミナルから行うことができます**。このように、クラウドでのシステム開発に必要なスキルや理解を深めることができます。初めての人でも簡単に手順を追うことができるので、ぜひ挑戦してみてください。
:::

どうでしたか？ 検証目的として、WSL Ubuntu で、Spring Boot Web アプリケーションを Azure App Service 環境でコンテナとして手軽に起動することができます。ぜひお試しください。今後も Azure の開発環境などを紹介していきますので、ぜひお楽しみにしてください。

## 推奨コンテンツ

https://qiita.com/studio_meowtoon/items/cbcfe1433885bae514db