1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第3回】ミニPCにKubernetes環境を構築するまで ~アプリデプロイ編~

1
Posted at

はじめに

この記事は、前回公開した「【第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

前提事項

この記事では、以下の環境がすでに準備されていることを前提とします。

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 の本質的な役割

Dockerfile は「コンテナイメージをビルドする プロセス を定義したファイル」であると同時に、その結果として作られるイメージの構成や状態も決定づけるものです。

つまり、

  • ビルドプロセスの指示書(How)
  • 最終的なイメージの設計図(What)

という2つの側面を持っている、という理解が私はしっくりきます。
(Dockerfile = レシピで、コンテナイメージ = レシピで作られた結果できた料理、と私は捉えています)

コンテナイメージ作成

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 マニフェストを作成します。

deployment.yaml
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 アドレスと指定ポートから直接アクセスできるようになります。

service.yaml
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.yamlservice.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 コマンドで STATUSRunning になっていれば、アプリのコンテナが正常に起動しています。
NAME                                     READY   STATUS    RESTARTS         AGE
k8s-sample-app-67fc6c667-m26rm           1/1     Running   2 (3m48s ago)    16d
  • kubectl get svc コマンドで作成した Service を確認し、TYPENodePort になっていれば 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/

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?