Spring Boot WEBサービスを AKS (Azure Kubernetes Service) で起動する (ACR カスタムコンテナイメージ)

# Spring Boot WEBサービスを AKS (Azure Kubernetes Service) で起動する (ACR カスタムコンテナイメージ)

## 目的

[Spring Boot WEBサービス](https://qiita.com/hiroxpepe/items/4a0f5e077155ce41e7ac)を [Azure Kubernetes Service](https://learn.microsoft.com/ja-jp/azure/aks/intro-kubernetes) 環境で起動して理解を深めます。  

## 実現すること

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

## 技術背景

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

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

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

Microsoft Azure Kubernetes Service (AKS) は、Kubernetes クラスタを管理するための Azure のフルマネージドサービスです。  

AKS の特徴とメリットはいかのとおりです。  

#### スケーラビリティ

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 を使用しています。  
+ [WSL](https://learn.microsoft.com/ja-jp/windows/wsl/about) の Ubuntu を操作していきますので macOS の方も参考にして頂けます。  

<details>

WSL (Microsoft Store アプリ版)

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

Ubuntu

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

Java JDK [※ Java JDK の導入と Hello World!](https://qiita.com/hiroxpepe/items/8650664e466906a57996)

```sh
$ java -version
openjdk version "11.0.17" 2022-10-18
OpenJDK Runtime Environment (build 11.0.17+8-post-Ubuntu-1ubuntu222.04)
OpenJDK 64-Bit Server VM (build 11.0.17+8-post-Ubuntu-1ubuntu222.04, mixed mode, sharing)
```

Maven [※ Maven の導入と Hello World!](https://qiita.com/hiroxpepe/items/40f7f199b9be7f9e3b5b)

```sh
$ mvn -version
Apache Maven 3.6.3
Maven home: /usr/share/maven
Java version: 11.0.17, vendor: Ubuntu, runtime: /usr/lib/jvm/java-11-openjdk-amd64
```

Docker Desktop

```sh
Version 4.16.3 (96739)
```

```sh
$ docker --version
Docker version 20.10.22, build 3a2c30b
```

```sh
$ docker-compose --version
Docker Compose version v2.15.1
```

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

</details>

※ この記事では基本的に Ubuntu のターミナルで操作を行います。

## "Hello World" を表示する手順

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

[Spring Boot WEBサービスの Hello World!](https://qiita.com/hiroxpepe/items/4a0f5e077155ce41e7ac) を参照して頂けます。  

### プロジェクトフォルダに移動  

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

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

### Java アプリをビルド(※参考)  

※ target/app.jar が作成されます。  
※ 下の コンテナイメージを作成する操作でも同時に target/app.jar が作成されるので必須ではありません。  

```sh
$ mvn clean install
```

### コンテナイメージを作成

コンテナイメージをビルド  

※ ローカルの Docker 環境 (Docker Desktop) に app-hello-spring-boot コンテナイメージが作成されます。  
※ コンテナイメージの作成時間が Unix エポックになるのは spring-boot:build-image の仕様です。  

```sh
$ mvn spring-boot:build-image \
    -Dspring-boot.build-image.imageName=app-hello-spring-boot
```

コンテナイメージの確認

```sh
$ docker images | grep app-hello-spring-boot-app
app-hello-spring-boot-app   latest   e37cc77f2b36   43 years ago   262MB
```

### Azure のアカウントを取得

公式 [Azure の無料アカウントを使ってクラウドで構築](https://azure.microsoft.com/ja-jp/free/)

### Azure CLI でサインイン

[Azure CLI をインストールする手順](https://qiita.com/hiroxpepe/items/20aeb54a676f190d5c96) を参照して頂けます。  

```sh
$ az login
```

### Azure 環境

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

リソースグループを作成

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

リソースグループ一覧表示

```sh
$ az group list
```

※ リソースグループを削除する場合

```sh
$ az group delete -n <group>
```

#### コンテナ レジストリ

コンテナ レジストリを作成  
※ --sku Free では作成できません。  
※ --name <name> はパブリックで一意の値が求められます。

```sh:Microsoft.ContainerRegistry/registries
$ az acr create \
    --resource-group rg-hello \
    --name cr20230212 \
    --sku Basic
```

コンテナ レジストリ一覧表示

```sh
$ az acr list
```

コンテナ レジストリログイン資格情報を表示

```sh
$ az acr update -n cr20230212 --admin-enabled true
$ az acr credential show \
    --resource-group rg-hello \
    --name cr20230212
```

```json
{
  "passwords": [
    {
      "name": "password",
      "value": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    },
    {
      "name": "password2",
      "value": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    }
  ],
  "username": "cr20230212"
}
```

※ コンテナ レジストリを削除する場合

```sh
$ az acr delete --n <acr-name>
```

コンテナ レジストリにログイン

```sh
$ az acr login --name cr20230212
```

コンテナイメージをコンテナ レジストリにプュシュ

```sh
$ docker tag app-hello-spring-boot cr20230212.azurecr.io/app-hello-spring-boot:latest
$ docker push cr20230212.azurecr.io/app-hello-spring-boot:latest
```

コンテナ レジストリのイメージを確認

```sh
$ az acr repository list --name cr20230212 --output table
Result
---------------------
app-hello-spring-boot
```

ローカルの コンテナイメージを Azure コンテナ レジストリにプュシュすることが出来ました。

#### AKS 環境

AKS クラスタの作成

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

AKS クラスタの一覧表示

```sh
$ az aks list
```

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

接続設定が成功した出力

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

#### Kubernetes (AKS) 環境

現在の接続先確認

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

接続先のリスト

```sh
$ kubectl config get-contexts
CURRENT   NAME             CLUSTER          AUTHINFO                         NAMESPACE
*         aks-hello        aks-hello        clusterUser_rg-hello_aks-hello
          docker-desktop   docker-desktop   docker-desktop
```

※ 接続先を local (docker-desktop) に戻す場合

```sh
$ kubectl config use-context docker-desktop
```

※ 接続先を削除する場合

```sh
$ kubectl config delete-context <context>
```

接続を確認

```sh
$ kubectl get nodes
NAME                                STATUS   ROLES   AGE     VERSION
aks-nodepool1-11584399-vmss000000   Ready    agent   4m43s   v1.24.9
```

コンテナ レジストリへの認証情報を作成  

```sh
$ kubectl create secret docker-registry regcred \
    --docker-server cr20230212.azurecr.io \
    --docker-username cr20230212 \
    --docker-password XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

Kubernetes のマニュフェストを修正

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

```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-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: app
  template:
    metadata:
      labels:
        app: app
    spec:
      containers:
      - name: app
        image: cr20230212.azurecr.io/app-hello-spring-boot:latest
        ports:
        - containerPort: 8080
      imagePullSecrets:
      - name: regcred
```

デプロイ  
※ くれぐれも接続先をご確認下さい。  

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

状態確認

```sh
$ kubectl get pods,services,deployments
NAME                                 READY   STATUS    RESTARTS   AGE
pod/app-deployment-7888b4769-wsc2f   1/1     Running   0          60s

NAME                  TYPE           CLUSTER-IP     EXTERNAL-IP    PORT(S)        AGE
service/app-service   LoadBalancer   10.0.164.159   20.48.75.231   80:31657/TCP   60s
service/kubernetes    ClusterIP      10.0.0.1       <none>         443/TCP        24m

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/app-deployment   1/1     1            1           60s
```

service/app-service の *EXTERNAL-IP 20.48.75.231* で外部からアクセス可能  

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

```sh
http://20.48.75.231/api/data
```

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

※ 別ターミナルから curl コマンドで確認

```sh
$ curl -v http://20.48.75.231/api/data
*   Trying 20.48.75.231:80...
* Connected to 20.48.75.231 (20.48.75.231) port 80 (#0)
> GET /api/data HTTP/1.1
> Host: 20.48.75.231
> 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: Mon, 27 Feb 2023 09:21:21 GMT
<
* Connection #0 to host 20.48.75.231 left intact
{"message":"Hello World!"}
```

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

※ Azure 側で SSL/TLS対応や HTTP/2プロトコル適用などはされていないようです。  

コンテナに接続

```sh
$ kubectl exec -it app-deployment-7888b4769-wsc2f -- /bin/bash
```

コンテナに接続後

```sh
$ pwd
/workspace
$ ls -la
total 20
drwxr-xr-x 1 cnb  cnb  4096 Jan  1  1980 .
drwxr-xr-x 1 root root 4096 Feb 27 08:10 ..
drwxr-xr-x 1 cnb  cnb  4096 Jan  1  1980 BOOT-INF
drwxr-xr-x 3 cnb  cnb  4096 Jan  1  1980 META-INF
drwxr-xr-x 3 cnb  cnb  4096 Jan  1  1980 org
```

コンテナの情報

```sh
$ cat /etc/*-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.6 LTS"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
NAME="Ubuntu"
ID=ubuntu
PRETTY_NAME="Paketo Buildpacks Base Bionic"
VERSION_ID="18.04"
HOME_URL="https://github.com/paketo-buildpacks/bionic-base-stack"
UBUNTU_CODENAME=bionic
VERSION="18.04.6 LTS (Bionic Beaver)"
ID_LIKE=debian
SUPPORT_URL="https://github.com/paketo-buildpacks/bionic-base-stack/blob/main/README.md"
BUG_REPORT_URL="https://github.com/paketo-buildpacks/bionic-base-stack/issues/new"
VERSION_CODENAME=bionic
```

## まとめ

+ Ubuntu のシンプルな構成の Java 開発環境で Spring Boot WEBサービスのカスタムコンテナイメージを AKS (Azure Kubernetes Service) 環境で起動させることが出来ました。

## 参考

公式 [Azure Kubernetes Service (AKS) コマンド リファレンス](https://learn.microsoft.com/ja-jp/cli/azure/service-page/azure%20kubernetes%20service%20(aks)?view=azure-cli-latest)