【初心者向けハンズオン】KubernetesでJava(Spring Boot)アプリデプロイ ~Step2:APコンテナ作成~

1. はじめに

本記事では、Kubernetes上にSpring Bootで構築したアプリを動作させるハンズオンをご紹介します。ひととおり実施して基本を理解すれば、ご自身で開発したアプリもKubernetes上で運用できるようになると思いますので、ぜひトライしてみて下さい。今回はStep2としてAPコンテナの作成方法をご説明します。

2. ハンズオン環境

Kubernetesがインストールされている環境を準備してください。今回はWindowsマシンのVirtualBox上に構築した仮想マシン上でKubernetesを構成しています。
・ホストマシン:Windows11
・仮想化ソフトウェア:VirtualBox 7.0
・仮想マシン:RHEL 8.5(Master Node:1台、Worker Node:2台)
・コンテナ・オーケストレーション:Kubernetes v1.29.12

オンプレでKuberntesインストールからやってみたいという方がいれば、下記を参考にして構築してもらえればと思います。
【初心者向け】Kubernetes学習向けのハンズオン(Linux(CentOS))

まだDBコンテナ作成が終わってないようでしたら下記を実施下さい。
【初心者向けハンズオン】KubernetesでJava(Spring Boot)アプリデプロイ ~Step1:DBコンテナ作成~

3. システム構成

Kubernetes上に構築するシステム構成を記載します。Web/AP、DBのシンプルなシステム構成で構築しています。AP PodについてはJavaが動作するDocker Imageをデプロイし、Executable Jarを起動することでアプリケーションを動作させます。

4. APコンテナの作成

4.1 Dockerイメージ作成
最初にDockerイメージを作成していきましょう。Dockerイメージとは、コンテナを作成・実行するためのテンプレートとなります。事前にDocker Hubにイメージを登録し、APコンテナ起動時にDocker Hubからイメージをpullして起動する流れとしています。Docker Hubを使用せずにプライベートレジストリを構築して利用する方法もありますので、どちらが良いかはご自身の用途に合わせて選択してください。

まだJarファイルを作成していない場合は、下記を参考にExecutable Jarを作成してください。
【初心者向け】Spring BootによるWebアプリ開発ハンズオン ~Step5:Linuxサーバへのデプロイ~
ローカル環境で動作させる時との違いとしては、データベースアクセス用のホスト名にStep1で作成したpostgresのサービス名を指定するという点になります。参考までに今回のハンズオン向けに作成したデータベースの設定ファイル(application.properties)を記載します。

#
# JDBC properties
#
spring.datasource.driver-class-name=org.postgresql.Driver
#spring.datasource.url=jdbc:postgresql://localhost:5432/quiz
spring.datasource.url=jdbc:postgresql://postgres:5432/quiz  ##localhostからpostgres(サービス名)に変更##
spring.datasource.username=postgres
spring.datasource.password=password

#spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDiaLect
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true

server.port=80

Executable Jarファイルが作成できたら、下記の通り適当なディレクトリに配置します。

[root@masternode ~]# cd /app/quizapp/
[root@masternode quizapp]#
[root@masternode quizapp]# ll
total 102588
-rw-r--r-- 1 root root 52519897 Feb  1 15:07 quizapp-1.0.jar
[root@masternode quizapp]#

続いてDockerfileを作成します。DockerfileとはDockerイメージ作成のための情報を記載したファイルとなります。各項目を簡単に説明します。

FROMDockerイメージのベースとなるイメージを指定します。ここでは、openjdk:21-jdkが使用できるイメージを指定しています。
ARGローカル変数を指定しています。
COPYPodに対するコピー処理を記載します。ここではローカルのjarファイルをapp.jarという名称でPodに配置するための設定を記載しています。
ENTRYPOINTPod起動時にデフォルトで実行するコマンドを記載します。ここではjava -jarコマンドでSpring Bootアプリを起動する処理を記載しています。

下記の通りDockerfileを作成します。

[root@masternode ~]# cd /app/quizapp/
[root@masternode quizapp]# vi Dockerfile
[root@masternode quizapp]# cat Dockerfile
FROM openjdk:21-jdk
ARG JAR_FILE=./*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]

[root@masternode quizapp]#

docker buildコマンドでDockerイメージを作成します。

[root@masternode quizapp]# docker build -t eeengineer1111/quizapp .
[+] Building 8.5s (8/8) FINISHED                                                                                                       docker:default
 => [internal] load build definition from Dockerfile                                                                                             0.1s
 => => transferring dockerfile: 142B                                                                                                             0.0s
 => [internal] load metadata for docker.io/library/openjdk:21-jdk                                                                                3.3s
 => [auth] library/openjdk:pull token for registry-1.docker.io                                                                                   0.0s
 => [internal] load .dockerignore                                                                                                                0.1s
 => => transferring context: 2B                                                                                                                  0.0s
 => [internal] load build context                                                                                                                2.0s
 => => transferring context: 52.53MB                                                                                                             2.0s
 => CACHED [1/2] FROM docker.io/library/openjdk:21-jdk@sha256:af9de795d1f8d3b6172f6c55ca9ba1c5768baa11bb2dc8af7045c7db9d4c33ac                   0.0s
 => [2/2] COPY ./*.jar app.jar                                                                                                                   1.8s
 => exporting to image                                                                                                                           0.7s
 => => exporting layers                                                                                                                          0.5s
 => => writing image sha256:f36301bfc8e12bab9e2b63db6726f4a0135cb64e56a30b4f283ef44432eab9e6                                                     0.0s
 => => naming to docker.io/eeengineer1111/quizapp                                                                                                0.1s
[root@masternode quizapp]#

docker imagesコマンドでDockerイメージが作成できていることを確認します。

[root@masternode quizapp]# docker images
REPOSITORY               TAG       IMAGE ID       CREATED       SIZE
eeengineer1111/quizapp   latest    b7eb804d5b85   2 weeks ago   557MB
[root@masternode quizapp]#

作成したDockerイメージが実行できるか確認しましょう。docker imagesrunコマンドを下記の通り実行して下さい。
ローカル環境からはpostgres Podのサービスに接続できないのでデータベース接続のところでエラーになってはしまいますが、作成したDockerイメージが実行できるか確認してみて下さい。

[root@masternode quizapp]# docker run eeengineer1111/quizapp

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.7)

2025-02-19T23:54:04.608Z  INFO 1 --- [  restartedMain] eeengineer.quizapp.QuizApplication       : Starting QuizApplication v1.0 using Java 21 with PID 1 (/app.jar started by root in /)
2025-02-19T23:54:04.637Z  INFO 1 --- [  restartedMain] eeengineer.quizapp.QuizApplication       : No active profile set, falling back to 1 default profile: "default"
2025-02-19T23:54:04.947Z  INFO 1 --- [  restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
~~Omission~~
2025-02-19T23:54:38.692Z ERROR 1 --- [  restartedMain] o.h.engine.jdbc.spi.SqlExceptionHelper   : The connection attempt failed.
2025-02-19T23:54:38.699Z  WARN 1 --- [  restartedMain] o.h.e.j.e.i.JdbcEnvironmentInitiator     : HHH000342: Could not obtain connection to query metadata

org.hibernate.exception.JDBCConnectionException: unable to obtain isolated JDBC connection [The connection attempt failed.] [n/a]
at org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:100) ~[app.jar:1.0]
at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:58) ~[app.jar:1.0]
~~Omission~~

4.2 Docker HubにDockerイメージをPush
作成したDockerイメージをDocker HubにPushします。まず、下記サイトを参考にDocker Hubでアカウントを作成してください。
https://docs.docker.jp/mac/step_five.html

アカウントが作成できたら、下記コマンドを実行してDocker Hubにログインします。

[root@masternode ~]# docker login
Log in with your Docker ID or email address to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com/ to create one.
You can log in with your password or a Personal Access Token (PAT). Using a limited-scope PAT grants better security and is required for organizations using SSO. Learn more at https://docs.docker.com/go/access-tokens/

Username: eeengineer1111
Password: 
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
docker login
Login Succeeded [root@masternode ~]#

docker pushコマンドを実行し、Docker Hubに作成したimageを登録します。

[root@masternode ~]# docker push eeengineer1111/quizapp
Using default tag: latest
The push refers to repository [docker.io/eeengineer1111/quizapp]
~~Omission~~
4611c85d409a: Pushed 
latest: digest: sha256:f59f4b3ba8365aa570ecf1c2b382aefdbebacaf0bc98943a79565d47bfbb4ddb size: 1166

docker searchコマンドを実行し、Docker HubにイメージがPushできていることを確認します。

[root@masternode ~]# docker search eeengineer1111/quizapp
NAME                                 DESCRIPTION                                     STARS     OFFICIAL
eeengineer1111/quizapp                                                               0
~~Ommission~~
[root@masternode ~]# 

4.3 AP Pod作成
Dockerイメージの準備ができたので、AP Podを作成していきましょう。下記の通りdeployment向けのマニフェストを作成します。
imageの項目にDocker Hubに登録したイメージ(eeengineer1111/quizapp)を指定して下さい。

[root@masternode ~]# cd /app/quizapp/manifest/
[root@masternode manifest]#
[root@masternode manifest]# vi quizapp-deployment.yaml
[root@masternode manifest]# cat quizapp-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: quizapp
  name: quizapp
  namespace: quizapp
spec:
  replicas: 3
  selector:
    matchLabels:
      app: quizapp
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: quizapp
    spec:
      containers:
      - image: eeengineer1111/quizapp
        ports:
        - containerPort: 8080
        name: quizapp
        resources: {}
status: {}
[root@masternode manifest]#

deploymentのマニフェストを適用します。下記の通りquizappのPodのSTATUSがRunningになっていれば成功です。

[root@masternode manifest]# kubectl apply -f quizapp-deployment.yaml
deployment.apps/quizapp created
[root@masternode manifest]#
[root@masternode manifest]# kubectl get pod -n quizapp
NAME                        READY   STATUS    RESTARTS   AGE
postgres-58c98dcd44-5hf7z   1/1     Running   0          68m
postgres-58c98dcd44-cbspd   1/1     Running   0          68m
postgres-58c98dcd44-rq9d9   1/1     Running   0          68m
quizapp-9446b7c78-dml2g     1/1     Running   0          18s
quizapp-9446b7c78-f89x7     1/1     Running   0          18s
quizapp-9446b7c78-gpqv6     1/1     Running   0          18s
[root@masternode manifest]#

続いてquizappのserviceを作成します。Step3でIngress Gateway経由で接続する際に必要となりますので、この時点で作成しておきましょう。下記の通りマニフェストを作成してください。

[root@masternode manifest]# vi quizapp-service.yaml
[root@masternode manifest]# cat quizapp-service.yaml
apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: quizapp
  name: quizapp
  namespace: quizapp
spec:
  type: NodePort
  ports:
  - name: http
    port: 80
    targetPort: 8080
    protocol: TCP
  selector:
    app: quizapp
status:
  loadBalancer: {}
[root@masternode manifest]#

serviceのマニフェストを適用します。下記の通りquizappのserviceが取得できれば成功です。

[root@masternode manifest]# kubectl apply -f quizapp-service.yaml
service/quizapp created
[root@masternode manifest]#
[root@masternode manifest]# kubectl get service -n quizapp
NAME       TYPE           CLUSTER-IP       EXTERNAL-IP       PORT(S)          AGE
postgres   LoadBalancer   10.106.194.35    192.168.100.200   5432:30168/TCP   9m7s
quizapp    NodePort       10.106.216.155   <none>            80:30247/TCP     9s
[root@masternode manifest]#

4.4 AP Podの動作確認
AP Podの動作確認をしていきましょう。まずはkubectl getコマンドに-o wideオプションをつけて、quizapp Podに直接アクセスするためのIPアドレスを取得します。

[root@masternode manifest]# kubectl get pod -o wide -n quizapp
NAME                        READY   STATUS    RESTARTS   AGE    IP               NODE          NOMINATED NODE   READINESS GATES
postgres-58c98dcd44-5hf7z   1/1     Running   0          70m    192.168.100.42   masternode    <none>           <none>
postgres-58c98dcd44-cbspd   1/1     Running   0          70m    192.168.100.43   workernode1   <none>           <none>
postgres-58c98dcd44-rq9d9   1/1     Running   0          70m    192.168.100.24   workernode2   <none>           <none>
quizapp-9446b7c78-dml2g     1/1     Running   0          118s   192.168.100.45   masternode    <none>           <none>
quizapp-9446b7c78-f89x7     1/1     Running   0          118s   192.168.100.26   workernode1   <none>           <none>
quizapp-9446b7c78-gpqv6     1/1     Running   0          118s   192.168.100.25   workernode2   <none>           <none>
[root@masternode manifest]#

curlコマンドでアプリケーションにアクセスしてみましょう。下記の通りアプリ画面の情報が取得できれば成功です。

[root@masternode ~]# curl http://192.168.100.45:8080/quiz/public
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ITエンジニア育成クイズ</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h3>ITエンジニア育成クイズ</h3>
        <a href= "/login" >ユーザ登録/ログイン</a>

~~Omission~~

                </td>
            </tr>
        </tbody>
    </table>

</div>

</body>
</html>[root@masternode ~]#

5. まとめ

APコンテナ作成のハンズオンは以上となります。Step2では個別のAP Podに対してアクセスできることを確認しました。Step3ではIngress経由でアクセスすることで、AP Podへのアクセスを振り分ける方法についてご紹介します。

6. 参考文献

コメント