はじめに
この記事は、前回公開した「【第2回】ミニPCにKubernetes環境を構築するまで ~構築編~」の続編です。
前回の記事では、ミニ PC に、Kubernetes クラスターを構築しました。
この記事では、Spring Boot で作成したシンプルなバックエンドアプリケーションを例に、
Kubernetes クラスター上にアプリケーションをデプロイする手順を解説します。
Docker イメージの作成から、Kubernetes リソース(Deployment / Service)の作成、
そして NodePort を利用した動作確認までを一通り行います。
デプロイするアプリについて
Spring Boot を利用した簡単なバックエンド API です。
/api/recipes にアクセスすると、サンプルのレシピ一覧が JSON 形式で返されます。
GET /api/recipes
レスポンス例:
[
{
"id": 1,
"title": "じゃがいもチーズおやき",
"description": "じゃがいも・チーズ・片栗粉で作る簡単おやき"
},
{
"id": 2,
"title": "鶏むね肉の照り焼き",
"description": "甘辛いタレがご飯に合う定番レシピ"
},
{
"id": 3,
"title": "豆腐ハンバーグ",
"description": "豆腐と鶏ひき肉でヘルシーに仕上げたハンバーグ"
}
]
アプリケーションのソースコードは以下の GitHub リポジトリに公開しています。
このリポジトリをクローンして作業を進めてください。
👉 ソースコード
git clone https://github.com/nkserveren26/k8s-sample-app.git
cd k8s-sample-app
前提事項
この記事では、以下の環境がすでに準備されていることを前提とします。
- ミニPC上に Kubernetes クラスターが構築済み
- 前回の記事「【第2回】ミニPCにKubernetes環境を構築するまで ~構築編~
」で構築した環境を利用します
- 前回の記事「【第2回】ミニPCにKubernetes環境を構築するまで ~構築編~
- Kubernetes 環境で
kubectlコマンドが利用可能- 以下のコマンドを実行し、
kubectlコマンドが正常に実行できることを確認してください。
- 以下のコマンドを実行し、
kubectl get nodes
- Docker Hub にリポジトリを作成済み
- 今回作成したアプリケーションのコンテナイメージをこのリポジトリに push します。
- Docker CLI が利用可能な環境で作業を行います。
- この環境でコンテナイメージのビルド・Docker Hub への push を行います。
- 以下のコマンドを実行し、Docker Hub にログインできることを確認してください。
docker login
デプロイまでの流れ
アプリのコンテナイメージの作成
Dockerfile 作成
まず、Spring Boot アプリケーションをコンテナ化するための Dockerfile を作成します。
Dockerfile とは、コンテナイメージをビルドするための手順を定義したファイルであり、Dockerfile で定義されたプロセスに沿ってコンテナイメージが作られていきます。
(コンテナイメージの レシピ(設計図) のようなものです)
Dockerfile に従ってコンテナイメージがビルドされていきますが、この過程でアプリケーションの成果物の配置、環境変数の設定、コンテナ起動時に実行するコマンドの定義などが行われます。
つまり、Dockerfile で定義されたプロセスを実行される過程でコンテナイメージの内容そのものが定義されていくことになるので、Dockerfile は結果的に、「どういう環境・状態のイメージができるか」も定義していることになります。
今回のアプリケーションは Java 21 で動作する Spring Boot アプリです。
Dockerfile はマルチステージビルドを採用し、ビルドと実行環境を分離することで、最終イメージを軽量化します。
以下の内容でプロジェクト直下に Dockerfile を作成します。
FROM maven:3.9.6-eclipse-temurin-21 AS builder
WORKDIR /app
# Copy the source code and run the build.
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests
# ---- Run Stage ----
FROM openjdk:21-jdk-slim
WORKDIR /app
# Copy the jar file created in the builder stage.
COPY --from=builder /app/target/*.jar app.jar
# open port 8080 for a jvm app.
EXPOSE 8080
# startup a jvm app.
ENTRYPOINT ["java", "-jar", "app.jar"]
📝ポイント解説
-
マルチステージビルド
- 1回目のステージで Maven によりアプリをビルドし、2回目のステージではビルド済み JAR のみを取り込みます。
- これにより、Maven やキャッシュ類を含まない軽量なコンテナイメージを作成できます。
-
-DskipTests- ビルド時間短縮のため、テストはスキップしています。
-
ENTRYPOINT- コンテナ起動時に実行するコマンドを指定します。
- 今回は Spring Boot アプリケーションを起動するコマンドを指定しています。
コンテナイメージ作成
Dockerfile の準備ができたら、次にコンテナイメージを作成します。
プロジェクトのルートディレクトリで以下のコマンドを実行します。
docker build -t k8s-sample-app:1.0.0 .
📝 コマンド解説
-
-tオプション- 作成するコンテナイメージにタグ(名前:バージョン)を付けます。
- ここでは
k8s-sample-app:1.0.0としています。
-
.- Dockerfile があるディレクトリを指定します。
- カレントディレクトリに Dockerfile がある場合は
.を指定します。
✅ イメージ作成の確認
ビルドが完了したら、以下のコマンドでイメージが作成されているかを確認します。
docker images
実行結果の例:
REPOSITORY TAG IMAGE ID CREATED SIZE
k8s-sample-app 1.0.0 2d3f8a0b8e3f 2 minutes ago 250MB
アプリのコンテナイメージを Docker Hub に push
コンテナイメージのタグ変更
ローカルで作成したコンテナイメージを Docker Hub に push するためには、
Docker Hub のリポジトリ名を含むタグに変更する必要があります。
以下のコマンドで、タグを付け直します。
docker tag k8s-sample-app:1.0.0 <DockerHubユーザー名>/k8s-sample-app:1.0.0
📝 コマンド解説
-
docker tag- 既存のイメージに新しいタグを付けます。
- これにより、Docker Hub への push 時にどのリポジトリへアップロードするかを指定できます。
-
<DockerHubユーザー名>- ご自身の Docker Hub アカウント名を指定します。
- たとえば、アカウント名が
hogedeveloperの場合は以下となります。
docker tag k8s-sample-app:1.0.0 hogedeveloper/k8s-sample-app:1.0.0
✅ タグの確認
タグ付けが完了したら、以下のコマンドで確認できます。
docker images
出力結果の例:
REPOSITORY TAG IMAGE ID CREATED SIZE
k8s-sample-app 1.0.0 2d3f8a0b8e3f 5 minutes ago 250MB
hogedeveloper/k8s-sample-app 1.0.0 2d3f8a0b8e3f 5 minutes ago 250MB
💡 補足:docker tag はイメージを複製しない
docker tag コマンドは、新しいイメージを作成するわけではありません。
既存のイメージに「別名(タグ)」を付けるだけの操作です。
docker tag k8s-sample-app:1.0.0 hogedeveloper/k8s-sample-app:1.0.0
上記を実行すると、同じ IMAGE ID を持つ2つのタグが一覧に表示されます。
REPOSITORY TAG IMAGE ID CREATED SIZE
k8s-sample-app 1.0.0 2d3f8a0b8e3f 5 minutes ago 250MB
hogedeveloper/k8s-sample-app 1.0.0 2d3f8a0b8e3f 5 minutes ago 250MB
つまり、実際のイメージデータは1つだけで、ストレージは増えません。
この仕組みを利用して、ローカル名と Docker Hub 用のリポジトリ名を使い分けることができます。
コンテナイメージを Docker Hub に push
Docker Hub 用にタグを付けたイメージを、実際に Docker Hub へ push します。
以下のコマンドを実行してください。
docker push <DockerHubユーザー名>/k8s-sample-app:1.0.0
📝 コマンド解説
-
docker push- ローカルにあるコンテナイメージを Docker Hub へアップロードします。
- タグ(<ユーザー名>/<リポジトリ名>:バージョン)が一致するリポジトリに push されます。
例として、Docker Hub のユーザー名が hogedeveloper の場合は以下のようになります。
docker push hogedeveloper/k8s-sample-app:1.0.0
push が完了すると、以下のような出力が表示されます。
The push refers to repository [docker.io/hogedeveloper/k8s-sample-app]
5bfa1c3388a3: Pushed
1a1b2c3d4e5f: Pushed
latest: digest: sha256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx size: 1573
これで、Docker Hub 上にコンテナイメージが登録されました。
ブラウザで Docker Hub の自分のリポジトリページにアクセスし、イメージが登録されていることを確認できます。
Kubernetes マニフェストの作成
Docker Hub にコンテナイメージを登録できたら、
次は Kubernetes 上でアプリを動かすための マニフェストファイル を作成します。
マニフェストは、今回作成した アプリケーションリポジトリ内 に配置します。
(例:k8s ディレクトリを作成して、その中に配置)
k8s-sample-app/
├─ src/
├─ pom.xml
└─ k8s/
├─ deployment.yaml
└─ service.yaml
ここでは以下の2つを作成します。
- Deployment:コンテナのデプロイとスケーリングを管理
- Service:Pod にアクセスするためのエンドポイントを提供
ディレクトリ構成の例は以下の通りです。
Deployment マニフェスト作成
アプリケーションの Pod をデプロイするための Deployment マニフェストを作成します。
apiVersion: apps/v1
kind: Deployment
metadata:
name: k8s-sample-app
labels:
app: k8s-sample-app
spec:
replicas: 1
selector:
matchLabels:
app: k8s-sample-app
template:
metadata:
labels:
app: k8s-sample-app
spec:
containers:
- name: k8s-sample-app
image: nkdeveloper26/k8s-sample-app:latest # あとでDocker HubにPushしたタグを指定
ports:
- containerPort: 8080
📝 設定ポイント
-
replicas- アプリケーションの Pod 数を指定しています。今回は1つ。
-
image- Docker Hub に push したコンテナイメージを指定します。
-
containerPort- コンテナ内でアプリが待ち受けるポート番号。Spring Boot のデフォルトは 8080。
Service マニフェスト作成
次に、Pod にアクセスするための Service リソースを作成します。
ここでは、アプリの動作確認を行うために NodePort タイプを使用します。
これにより、Kubernetes ノードの IP アドレスと指定ポートから直接アクセスできるようになります。
apiVersion: v1
kind: Service
metadata:
name: k8s-sample-app-service
spec:
type: NodePort
selector:
app: k8s-sample-app
ports:
- port: 8080 # Serviceが受け付けるポート
targetPort: 8080 # Podのコンテナポート
nodePort: 30080 # Node上でアクセスできるポート(30000〜32767で任意指定)
📝 設定ポイント
- type: NodePort
- クラスタ外からアクセス可能にするために指定しています。
-
port/targetPort- Service 内部と Pod 内で利用するポート番号を指定しています。
-
portは Service のポート、targetPortはコンテナ(Spring Boot)のポートを指します。 - どちらも 8080 に統一しています。
-
nodePort- ノード外部からアクセスする際のポート番号です。
-
30000〜32767の範囲で指定できます。 - 今回は例として
30080を指定しています。
これで、Kubernetes にデプロイする準備が整いました。
次の章では、実際にマニフェストを Kubernetes 環境へ適用して、アプリをデプロイしてみます。
💡 補足:nodePort で指定できるポート範囲について
nodePort で利用できるポート番号には範囲が決まっており、デフォルトでは 30000〜32767 が割り当てられています。
この範囲は、Kubernetes コントロールプレーンのコンポーネントである kube-apiserver によって管理されています。
もし異なる範囲を使用したい場合は、kube-apiserver の起動オプションである --service-node-port-range を指定することで変更可能です。
たとえば、以下のように設定することで 20000〜40000 の範囲を利用できるようになります。
--service-node-port-range=20000-40000
kube-apiserver の設定は通常、/etc/kubernetes/manifests/kube-apiserver.yaml に記載されています。
このファイル内の spec.containers.command セクションに上記のオプションを追加することで設定を反映できます。
注意
nodePort のポート範囲変更は実際に検証した内容ではなく、Kubernetes の公式ドキュメントなどをもとにした参考情報です。
変更の際は十分にご注意ください。
Kubernetes 環境にデプロイ
これまでに作成した Deployment および Service のマニフェストを実際に Kubernetes 環境へ適用し、アプリケーションをデプロイします。
Kubernetes 環境にマニフェストファイルを配置
まず、Kubernetes クラスタへ適用するために、ローカルで作成したマニフェストファイル(deployment.yaml・service.yaml)をクラスタ環境上に転送します。
今回は、ローカル環境から、前回構築した Kubernetes ノード(コントロールプレーンノード)へ scp コマンドを使って転送します。
# deployment.yaml と service.yaml を転送
scp deployment.yaml service.yaml <OS ユーザー名>@<Kubernetesノードの IP アドレス>:/home/<OS ユーザー名>/manifests
💡 補足
-
<KubernetesノードのIPアドレス>:クラスタを構築したノードの IP アドレスを指定します。 -
<OS ユーザー名>:Ubuntu 環境で利用しているユーザー名を指定します。 - SSH 鍵で認証している場合は、-i オプションで秘密鍵を指定できます。
scp -i ~/.ssh/id_rsa deployment.yaml service.yaml <OSユーザー名>@<KubernetesノードのIPアドレス>:/home/<OSユーザー名>/manifests/
-
/home/<OSユーザー名>/manifestsは、マニフェスト配置用のディレクトリとして任意で作成しておくと管理しやすいです。
Kubernetes リソース作成
マニフェストファイルを配置したら、kubectl コマンドでリソースを作成します。
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
それぞれのコマンド実行後、リソースが作成されたことを確認します。
kubectl get pods
kubectl get svc
💡 補足
-
kubectl get podsコマンドでSTATUSがRunningになっていれば、アプリのコンテナが正常に起動しています。
NAME READY STATUS RESTARTS AGE
k8s-sample-app-67fc6c667-m26rm 1/1 Running 2 (3m48s ago) 16d
-
kubectl get svcコマンドで作成した Service を確認し、TYPEがNodePortになっていれば OK です。-
PORT(S)の右側に表示されるポート番号(例:30080)が、外部アクセス時に指定するポートです。
-
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
k8s-sample-app-service NodePort 10.106.73.222 <none> 8080:30080/TCP 26d
動作確認
Service を NodePort タイプで公開している場合は、以下の URL にアクセスすることでアプリの動作を確認できます。
http://<ノードのIPアドレス>:<NodePort番号>/api/recipe
ブラウザまたは curl コマンドでアクセスし、JSON 形式のレスポンス(レシピ一覧)が返ってくればデプロイ成功です 🎉
おわりに
今回は、ミニ PC 上に構築した Kubernetes クラスタへ、Spring Boot アプリケーションをデプロイしました。
ローカルでビルドしたアプリをコンテナ化し、Kubernetes 上で実際に動かすところまで確認できました。
ここまでで、
- コンテナイメージの作成と Docker Hub への登録
- Deployment / Service のマニフェスト作成
- Kubernetes へのデプロイと動作確認
といった、アプリを Kubernetes に載せるまでの一連の流れを体験できたことになります。
次回は、Cloudflare Tunnel を使って、インターネット経由でアプリにアクセスできるようにする手順を解説します。
Kubernetes クラスタ上に構築したアプリケーションを Cloudflare Tunnel を使って外部公開する際の構成や、Ingress Controller・Cloudflare の設定など、実践的な内容を扱う予定です。
参考資料
https://kubernetes.io/docs/concepts/services-networking/service/
https://kubernetes.io/docs/reference/command-line-tools-reference/kube-apiserver/