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

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

こんにちは、@studio_meowtoon です。今回は、Azure Kubernetes Service 環境で Spring Boot Web アプリケーションをコンテナとして起動する方法を紹介します。
![spring-boot_on_azure-kubernetes-service.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/cfc7a5cc-43cb-03c4-23d4-f10187629198.png)

## 目的

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

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

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

## 実現すること

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

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

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

## 技術トピック

### Microsoft Azure Kubernetes Service (AKS) とは？  

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

### [Microsoft Azure Kubernetes Service (AKS)](https://learn.microsoft.com/ja-jp/azure/aks/intro-kubernetes)

:::note info
Azure 上で実行されるマネージド Kubernetes サービスです。AKS は、クラウド上で Kubernetes クラスターを簡単に展開、管理、スケーリングできるようにすることで、Kubernetes の運用を簡素化します。

|キーワード|内容|
|:--|:--|
|スケーラビリティ|AKS は、需要の変化に合わせてアプリケーションをスケールアップ/ダウンできます。Kubernetes の標準機能を使い、Pod の数を調整することで、クラスター全体のリソース使用率を最適化できます。|
|自動化|AKS は、クラスターのデプロイ、アップグレード、監視、スケーリング、および管理に関連するタスクを自動化します。これにより、ユーザーは Kubernetes に関連する複雑なタスクを簡素化できます。|
|セキュリティ|AKS は、ユーザーが Kubernetes クラスタをセキュアに設定するのに役立ちます。AKS は、構成可能なネットワークポリシー、構成済みのログイン、Role-Based Access Control (RBAC) などをサポートしています。|
|ポータビリティ|AKS は、クラウドネイティブアプリケーションをどこでも実行できるようにするため、オープンソースの Kubernetes を使用しています。AKS は、Azure の他のサービス、オンプレミス環境、および他のクラウドプロバイダーにデプロイできます。|
|プロダクションレディ|AKS は、高可用性、監視、スケーラビリティ、およびセキュリティに焦点を当て、プロダクションレディな Kubernetes クラスターを提供します。AKS は、SLA で 99.95％ の可用性を提供します。|
:::

</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/ef38ba2d5e913e343380#kubernetes-%E7%92%B0%E5%A2%83%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)

```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>

#### AKS 環境
:::note alert
AKS を作成すると、Kubernetes クラスター用の多数のリソースが自動的に作成されます。これらのリソースは、Azure Portal 上で確認することができます。ただし、AKS のリソースを削除すると自動的に関連リソースも削除されますが、共有している Azure サブスクリプションで検証される場合など、ご注意ください。
:::
![aks.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/38d5b18f-0350-d765-01e4-01de32735c42.png)
AKS クラスターを作成します。  
※ Kubernetes 基盤の環境作成に少し時間がかかります。  

```sh:Microsoft.ContainerService/ManagedClusters
$ az aks create \
    --resource-group rg-hello \
    --name aks-hello \
    --node-count 1 \
    --generate-ssh-keys
```

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

:::note info
このコマンドは、Azure 上に新しい Kubernetes クラスターを作成しています。

|コマンド|内容|
|:--|:--|
|az aks create|Azure 上に、Kubernetes クラスターを作成するコマンドです。|

|オプション|値|内容|
|:--|:--|:--|
|--resource-group|rg-hello|Kubernetes クラスターを作成するリソースグループの名前です。|
|--name|aks-hello|作成する Kubernetes クラスターの名前です。|
|--node-count|1|Kubernetes クラスターにデプロイするノードの数を指定します。|
|--generate-ssh-keys|--|Kubernetes クラスターに SSH キーを自動生成するかどうかを指定します。このオプションを指定することで、ユーザーが手動で SSH キーを生成する必要がなくなります。|
:::

</details>

AKS クラスターの一覧を表示してみます。

```sh
$ az aks list
```

:::note warn
AKS クラスターを削除する場合、以下のコマンドを使用します。
:::

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

設定ファイルの権限を修正します。 
※ 初回のみ必要です。 

```sh
$ chmod 600 /home/$USER/.kube/config
```

AKS クラスターと接続します。  
※ 既存設定の上書きを許可する為、yes を選択します。    

```sh
$ az aks get-credentials \
    --resource-group rg-hello \
    --name aks-hello
```

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

:::note info
このコマンドは、Azure 上に作成された Kubernetes クラスターに接続するための認証情報を取得しています。

|コマンド|内容|
|:--|:--|
|az aks get-credentials|Azure 上の、Kubernetes クラスターに接続するための認証情報を取得します。|

|オプション|値|内容|
|:--|:--|:--|
|--resource-group|rg-hello|Kubernetes クラスターが作成されたリソースグループ名を指定します。|
|--name|aks-hello|作成する Kubernetes クラスターの名前を指定します。|

このコマンドを実行すると、指定されたリソースグループと Kubernetes クラスターの認証情報がローカルに保存され、**kubectl コマンドで** **Kubernetes クラスターに接続**するために使用されます。これにより、Kubernetes クラスターに対してコマンドを発行する際に、手動で認証情報を指定する必要がなくなります。
:::

</details>

接続設定が成功した場合の出力は、以下のようになります。

```sh
Merged "aks-hello" as current context in /home/$USER/.kube/config
```

:::note info
ここまでで **Azure** 上に構築した **Kubernetes クラスターに接続**できました。ここからはその Kubernetes クラスターをリモートでコマンド操作していきます。
:::

### Kubernetes クラスター (AKS) の操作

:::note alert
AKS にデプロイするために、Minikube を経由して kubectl を使用する代わりに、Azure CLI で kubectl を直接インストールする手順を紹介しています。
:::

Kubernetes コマンドライン ツール、kubectl をインストールします。

```sh
$ sudo az aks install-cli
```

Minikube で使用したシンボリックリンクを削除します。

```sh
$ unalias kubectl
```

kubectl のバージョンを確認します。

```sh
$ kubectl version --short
Client Version: v1.26.2
Kustomize Version: v4.5.7
Server Version: v1.24.9
```

現在の接続先を確認します。

```sh
$ kubectl config current-context
aks-hello
```

:::note alert
**Kubernetes クラスターに接続していることを確認する**ことは、誤ったクラスターに対してコマンド操作を実行することを防ぐために重要です。例えば、誤ったクラスターに対してデプロイメントを適用したり、Pod を削除したりすると、**誤操作が原因**で**サービスの停止**や**データの消失**などの致命的な問題を引き起こす可能性があります。
:::

### Kubernetes マニフェスト作成  

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

https://qiita.com/studio_meowtoon/items/ef38ba2d5e913e343380#kubernetes-%E3%83%9E%E3%83%8B%E3%83%A5%E3%83%95%E3%82%A7%E3%82%B9%E3%83%88%E4%BD%9C%E6%88%90

Kubernetes のマニュフェストを修正します。  
※ $USER の部分はご自身のコンテナリポジトリに読み替えて下さい。  

```sh
$ vim kube-all-in-one.yaml
```

```yaml:kube-all-in-one.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 8080
  selector:
    app: app
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
      - name: app
        image: $USER/app-hello-spring-boot:latest
        ports:
        - containerPort: 8080
```

Kubernetes クラスターにデプロイします。

```sh
$ kubectl apply -f kube-all-in-one.yaml
service/app-service created
deployment.apps/app-deployment created
```

Kubernetes クラスターの状態を確認します。

```sh
$ kubectl get pods,services,deployments
NAME                       READY   STATUS    RESTARTS   AGE
pod/app-b876686f6-87kjn    1/1     Running   0          3m42s

NAME                  TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)        AGE
service/app-service   LoadBalancer   10.0.52.170   xx.xx.xx.xx   80:30634/TCP   3m42s
service/kubernetes    ClusterIP      10.0.0.1      <none>          443/TCP        52m

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-deployment   1/1     1            1           3m42s
```

### コンテナ動作の確認

service/app-service の **EXTERNAL-IP xx.xx.xx.xx** で外部からアクセス可能です。   

WEBブラウザで確認  
※ URLは環境で読み替えて下さい。  

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

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

```sh
$ curl -v https://xx.xx.xx.xx/api/data
*   Trying xx.xx.xx.xx:80...
* Connected to xx.xx.xx.xx (xx.xx.xx.xx) port 80 (#0)
> GET /api/data HTTP/1.1
> Host: xx.xx.xx.xx
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Sat, 11 Mar 2023 07:47:53 GMT
<
* Connection #0 to host xx.xx.xx.xx left intact
{"message":"Hello World!"}
```

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

### コンテナに接続

別ターミナルから Spring Boot カスタムコンテナに接続してみます。

```sh
$ kubectl exec -it app-b876686f6-87kjn -- /bin/bash
```

コンテナに接続後にディレクトリを確認します。 
※ コンテナから出るときは ctrl + D を押します。  

```
# pwd
/app
# ls -la
total 17248
drwxr-xr-x 1 root root     4096 Mar 10 13:00 .
drwxr-xr-x 1 root root     4096 Mar 11 07:42 ..
-rw-r--r-- 1 root root 17650415 Mar 10 12:59 app.jar
```

コンテナの情報を表示してみます。

```
# cat /etc/*-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=20.04
DISTRIB_CODENAME=focal
DISTRIB_DESCRIPTION="Ubuntu 20.04.5 LTS"
NAME="Ubuntu"
VERSION="20.04.5 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.5 LTS"
VERSION_ID="20.04"
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"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```
こちらは、ターミナルで top 表示した画像になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/49128913-56a7-c139-ac70-505cd37f3ee8.png)

:::note warn
このコンテナは Ubuntu をベースに作成されています。つまり、Ubuntu と同じように扱うことができます。
:::

## まとめ

Azure Kubernetes Service (AKS) 環境で、kube-all-in-one.yaml という YAML 形式のマニュフェストファイルを用いて、Spring Boot Web サービスのカスタムコンテナイメージをデプロイすることができました。

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

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