Kubernetes 環境で Spring Boot Webサービスを起動する

# Kubernetes 環境で Spring Boot Webサービスを起動する

こんにちは、@studio_meowtoon です。今回は、WSL Ubuntu 22.04 の Kubernetes 環境で Spring Boot Web アプリケーションをコンテナとして起動する方法を紹介します。
![spring-boot_on_kubernetes.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/e66db804-d483-a4a9-758a-efcbae687333.png)

## 目的

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

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

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

## 実現すること

ローカル環境の WSL Ubuntu の Kubernetes クラスターに、kube-all-in-one.yaml という YAML 形式のマニュフェストファイルを用いて、Spring Boot カスタムコンテナイメージをデプロイします。

:::note alert
ご自身のPCに、Kubernetes クラスターを構築するには、[**Docker Desktop**](https://www.docker.com/products/docker-desktop/) を使用する方法があり、そちらが一般的です。 しかし、この記事では Minikube を使用して Kubernetes クラスターを直接コマンドから操作することで、Kubernetes の基礎的な使い方を学習することを目的としています。ご注意ください。
:::

## 技術トピック

### Kubernetes とは？  

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

### [Kubernetes (クーバネティス)](https://kubernetes.io/ja/)

:::note info
Kubernetes は、オープンソースのコンテナオーケストレーションツールで、Google 社によって開発されました。Kubernetes は、コンテナ化されたアプリケーションの自動デプロイ、スケーリング、および管理を行うためのプラットフォームです。

|特徴|
|:--|
|Kubernetes は、コンテナをグループ化して、そのグループを管理する抽象的な概念である **ポッド** を使用します。また、複数のポッドを管理するための **デプロイメント** や、ポッド間の通信を制御する **サービス** などのリソースも提供しています。|
|Kubernetes を使用することで、アプリケーションのスケーリングや障害時の自動復旧などの運用作業を簡単に行うことができます。また、複数のクラウドプロバイダーやオンプレミス環境でも動作するため、ハイブリッド環境でも利用されています。|
|Kubernetes は、オープンソースであり、多くの企業やコミュニティによって開発・改良が行われています。そのため、今後もさらなる機能の向上や拡張性の向上が期待されています。|
:::

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

### Kubernetes 環境インストール

※ [Minikube](https://kubernetes.io/ja/docs/setup/learning-environment/minikube/) をインストールします。

<details>
<summary>Minikube とは？</summary>

:::note info
Minikube (ミニクーベ) は、Kubernetes クラスターをローカル環境で実行するためのツールです。

|特徴とメリット|
|:--|
|Kubernetes は、複数のコンテナ化されたアプリケーションを管理するためのオーケストレーションツールであり、複雑なアプリケーションを実行するために必要です。|
|Minikube は、ローカルで Kubernetes を実行することで、開発者がアプリケーションのテストや実験を行うために必要なリソースを提供します。Minikube は、シングルノードの Kubernetes クラスターを構築するために使用され、ローカルのマシンで動作するため、Kubernetes の操作方法を学ぶことができます。|
|Minikube を使用すると、Kubernetes クラスターの設定、管理、およびデプロイメントを簡単に行うことができます。また、Minikube は多くの機能を備えており、様々なアドオンを使用して機能を拡張することができます。|
:::

</details>

```sh
$ curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb
$ sudo dpkg -i minikube_latest_amd64.deb
```

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

:::note info
Minikube と呼ばれるローカルの Kubernetes クラスターをインストールします。

|コマンドと引数|内容|
|:--|:--|
|curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube_latest_amd64.deb|Minikube の最新バージョンの .deb パッケージをダウンロードします。.deb は Debian ベースの Linux ディストリビューション用のパッケージ形式です。|
|sudo dpkg -i minikube_latest_amd64.deb|ダウンロードした .deb ファイルを使用して Minikube をインストールします。このコマンドは、必要なすべての依存関係を自動的に解決し、Minikube を正しくセットアップするために必要なファイルをインストールします。|

これにより、Minikube がインストールされ、ローカルで Kubernetes クラスターをセットアップする準備が整います。これにより、開発者はローカルで Kubernetes クラスターを利用してアプリケーションを開発、テスト、デプロイすることができます。
:::

</details>

Kubernetes クラスターを開始します。

```sh
$ minikube start
```

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

```sh
$ minikube start
😄  Ubuntu 22.04 (amd64) 上の minikube v1.29.0
✨  docker ドライバーが自動的に選択されました。他の選択肢: none, ssh
📌  root 権限を持つ Docker ドライバーを使用
👍  minikube クラスター中のコントロールプレーンの minikube ノードを起動しています
🚜  ベースイメージを取得しています...
💾  ロード済み Kubernetes v1.26.1 をダウンロードしています...
    > preloaded-images-k8s-v18-v1...:  397.05 MiB / 397.05 MiB  100.00% 16.46 M
    > gcr.io/k8s-minikube/kicbase...:  407.18 MiB / 407.19 MiB  100.00% 10.19 M
🔥  docker container (CPUs=2, Memory=2200MB) を作成しています...
🐳  Docker 20.10.23 で Kubernetes v1.26.1 を準備しています...
    ▪ 証明書と鍵を作成しています...
    ▪ コントロールプレーンを起動しています...
    ▪ RBAC のルールを設定中です...
🔗  bridge CNI (コンテナーネットワークインターフェース) を設定中です...
    ▪ gcr.io/k8s-minikube/storage-provisioner:v5 イメージを使用しています
🔎  Kubernetes コンポーネントを検証しています...
🌟  有効なアドオン: default-storageclass, storage-provisioner
💡  kubectl が見つかりません。kubectl が必要な場合、'minikube kubectl -- get pods -A' を試してください
🏄  終了しました！kubectl がデフォルトで「minikube」クラスターと「default」ネームスペースを使用するよう設定されました
```

</details>

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

Kubernetes のマニュフェストファイルを作成します。

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

ファイルの内容

```yaml:kube-all-in-one.yaml
apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  type: LoadBalancer
  selector:
    app: app
  ports:
  - port: 80
    targetPort: 8080
---
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: app-hello-spring-boot
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
```

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

:::note info
このファイルは Kubernetes オブジェクトを定義する YAML 形式のファイルであり、以下のような内容が含まれています。

+ Service オブジェクトを定義しています。
    + name フィールドで app-service という名前を指定しています。
    + type フィールドで LoadBalancer を設定しています。これにより、Service がクラスタ外部に公開され、外部からのアクセスが可能になります。
    + selector フィールドで、app というラベルを持つ Pod を選択するように指定しています。
    + ports フィールドで、ポート 80 を開放し、targetPort を 8080 に設定しています。

+ Deployment オブジェクトを定義しています。
    + name フィールドで app という名前を指定しています。
    + replicas フィールドで、Pod を1つだけ作成するように指定しています。
    + selector フィールドで、app というラベルを持つ Pod を選択するように指定しています。
    + template フィールドで、Pod のテンプレートを指定しています。
        + metadata フィールドで、Pod に app というラベルを付与しています。
        + spec フィールドで、Pod のスペックを指定しています。
            + containers フィールドで、コンテナの設定を指定しています。
                + name フィールドで、コンテナの名前を指定しています。
                + image フィールドで、コンテナイメージの名前を指定しています。
                + imagePullPolicy フィールドで、コンテナイメージの取得方法を指定しています。
                + ports フィールドで、コンテナが使用するポートを指定しています。ここでは 8080 というポートを指定しています。
:::

</details>

### Kubernetes クラスターにデプロイ

kubectl をダウンロードしてエイリアスを設定します。

```sh
$ minikube kubectl -- get po -A
$ alias kubectl="minikube kubectl --"
```

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

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

Kubernetes クラスター接続先を確認します。

```sh
$ kubectl config current-context
minikube
```

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

:::note info
**kubectl config current-context** コマンドは、現在の Kubernetes クラスターのコンテキスト(環境)を表示するために使用されます。

|内容|
|:--|
Kubernetes には、複数のクラスター、ユーザー、名前空間などを管理するためのコンテキストがあります。**kubectl config current-context** コマンドは、現在アクティブなコンテキストを表示するために使用されます。|
|コンテキストは、**~/.kube/config** ファイルに保存され、Kubernetes クラスターに接続するときに使用される認証情報、クラスター情報、名前空間情報などを含んでいます。|
|つまり、このコマンドを実行すると、現在の Kubernetes クラスターのコンテキストが表示されます。これにより、どのクラスターに接続しているか、どのユーザーでログインしているか、どの名前空間にいるかなどを確認できます。|
|また、複数のコンテキストを切り替えることもできます。これは、複数の Kubernetes クラスター、プロジェクト、環境を管理する場合に便利です。|

:::

</details>

ローカル Docker のコンテナイメージを Minikube に取り込みます。

```sh
$ minikube image load app-hello-spring-boot:latest
```

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

```sh
$ minikube image ls | grep app-hello-spring-boot
docker.io/library/app-hello-spring-boot:latest
```

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

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

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

:::note info
**kubectl apply** コマンドは、Kubernetes クラスターに新しいリソースを作成または更新するために使用されます。

|内容|
|:--|
|**kubectl apply** コマンドを使用して、kube-all-in-one.yaml という **YAML** ファイルに定義された Kubernetes リソースをクラスターに作成または更新します。|
|この YAML ファイルは、Pod、Service、Deployment、ConfigMap、Secret などの複数の Kubernetes リソースを定義することができます。|
|つまり、このコマンドを実行すると、YAML ファイルに定義されたすべてのリソースが Kubernetes クラスターに作成または更新されます。|
|このコマンドにより、アプリケーションやその他のリソースをクラスターに展開することができます。このコマンドは、DevOps や開発者が、アプリケーションのデプロイメントや更新を行う際に頻繁に使用されます。|

:::

</details>

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

```sh
$ kubectl get pods,services,deployments
NAME                      READY   STATUS    RESTARTS   AGE
pod/app-7656fd56b4-bsq8q   1/1     Running   0          10s

NAME                  TYPE          CLUSTER-IP     EXTERNAL-IP   PORT(S)          AGE
service/app-service   LoadBalancer  10.105.5.226   <pending>     80:31418/TCP     10s
service/kubernetes    ClusterIP     10.96.0.1      <none>        443/TCP          34m

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

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

:::note info
**kubectl get** コマンドは、現在の Kubernetes クラスターの状態を取得するために使用されます。

|内容|
|:--|
|**kubectl get** コマンドを使用して、**Pods**、**Services**、**Deployments** という3つのリソースの情報を取得します。pods、services、deployments は、Kubernetes クラスター内の主要なリソースの一部であり、それぞれ次のような情報を提供します。|
|**pods** クラスター内の Pod (コンテナ実行環境) の状態を表示します。
**services** クラスター内の Service (アプリケーションの公開) の状態を表示します。
**deployments** クラスター内の Deployment (Pod の自動スケーリング、更新) の状態を表示します。|
|つまり、このコマンドを実行すると、Kubernetes クラスター内の **Pods**、**Services**、**Deployments** の現在の状態が表示されます。|
|このコマンドにより、クラスター内のリソースの数や状態、アプリケーションの展開状況などを確認できます。また、この情報は、デバッグ、トラブルシューティング、監視、スケーリングなど、クラスターの管理に役立ちます。|

:::

</details>

:::note warn
Kubernetes クラスターを削除するには以下のコマンドを使用します。
:::

```sh
$ minikube delete --all
```

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

**app-service** に接続する URL を取得します。

```sh
$ minikube service app-service --url
http://127.0.0.1:46299
❗  Docker ドライバーを linux 上で使用しているため、実行するにはターミナルを開く必要があります。
```

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

:::note info
**minikube service** コマンドは、app-service という名前の Kubernetes Service が公開しているアプリケーションの URL を表示するために使用されます。

|内容|
|:--|
**minikube service** コマンドを使用して、Kubernetes クラスター内の app-service Service を公開し、アプリケーションが公開された URL を取得します。**--url** フラグは、この URL を表示するために使用されます。|
|つまり、このコマンドを実行すると、app-service Service が公開しているアプリケーションの URL が表示されます。この URL をブラウザに入力することで、アプリケーションにアクセスすることができます。|
|このコマンドは、ローカル環境でアプリケーションをテストする場合や、デプロイされたアプリケーションにアクセスする場合に非常に便利です。|

:::

</details>

WEBブラウザで確認します。

```sh
http://127.0.0.1:46299/api/data
```

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

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

```sh
$ curl -v http://127.0.0.1:46299/api/data
*   Trying 127.0.0.1:46299...
* Connected to 127.0.0.1 (127.0.0.1) port 46299 (#0)
> GET /api/data HTTP/1.1
> Host: 127.0.0.1:46299
> 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: Fri, 10 Mar 2023 13:33:14 GMT
<
* Connection #0 to host 127.0.0.1 left intact
{"message":"Hello World!"}
```

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

### Kubernetes ダッシュボードで確認

Kubernetes ダッシュボードをインストールします。

```sh
$ minikube dashboard
```

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

```sh
$ minikube dashboard
🔌  ダッシュボードを有効化しています...
    ▪ docker.io/kubernetesui/metrics-scraper:v1.0.8 イメージを使用しています
    ▪ docker.io/kubernetesui/dashboard:v2.7.0 イメージを使用しています
💡  いくつかのダッシュボード機能は metrics-server アドオンを必要とします。全機能を有効にするためには、次のコマンドを実行します:

        minikube addons enable metrics-server


🤔  ダッシュボードの状態を検証しています...
🚀  プロキシーを起動しています...
    > kubectl.sha256:  64 B / 64 B [-------------------------] 100.00% ? p/s 0s
    > kubectl:  45.80 MiB / 45.80 MiB [------------] 100.00% 13.08 MiB p/s 3.7s
🤔  プロキシーの状態を検証しています...
🎉  デフォルトブラウザーで http://127.0.0.1:32877/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ を開いています...
👉  http://127.0.0.1:32877/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/
```

</details>

Web ブラウザで以下の URL にアクセスします。

```sh
http://127.0.0.1:32877/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/
```

Kubernetes ダッシュボードが表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3206449/ac3ad471-0da3-3f00-3a30-9e90dedac0b8.png)
ダッシュボードからさまざまな情報を確認することができます。
### コンテナに接続

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

```sh
$ kubectl exec -it app-7656fd56b4-bsq8q -- /bin/bash
```

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

:::note info
**kubectl exec** コマンドは、Kubernetes クラスター上の特定の Pod に対して、対話的な bash シェルを実行するためのコマンドです。

|内容|
|:--|
|**kubectl exec** コマンドを使用して、指定された Pod (ここではapp-deployment-7656fd56b4-bsq8q) 内のコンテナで、**/bin/bash** シェルを開始します。**-it** フラグは、ターミナルで対話的なモードでシェルを開始することを指定しています。|
|つまり、このコマンドを実行すると、指定した Pod 内のコンテナに対して、bash シェルを開始し、コマンドや操作を直接実行することができます。|
|このコマンドは、デバッグやトラブルシューティングのために非常に便利であり、アプリケーションが正常に動作しているかどうかを確認することができます。|
:::

</details>

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

```
# pwd
/app
# ls -la
total 17248
drwxr-xr-x 1 root root     4096 Mar 10 12:23 .
drwxr-xr-x 1 root root     4096 Mar 10 13:16 ..
-rw-r--r-- 1 root root 17650415 Mar  9 07: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
```

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

## まとめ

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

:::note warn
クラウド開発においては、**Kubernetes の基礎的な理解**は重要です。また、Ubuntu を使用することで Linux の知識も身につけることができます。最初は難しく感じるかもしれませんが、少しずつ進めていくことで自信を持って取り組むことができるようになります。
:::

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

## 推奨コンテンツ

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