DockerでコンテナイメージをビルドできたSpring Boot開発者が次に直面するのが、「KubernetesのManifestをどう書けばいいのか」という問題ですよね。特にヘルスチェックや機密設定の扱いはK8s特有のパターンがあります。

この記事ではDeployment・Service・ConfigMap・SecretのManifestを順を追って説明します。DockerイメージのビルドとpushについてはSpring BootアプリをDockerコンテナで動かす方法にまとめています。

前提条件

この記事では以下が完了していることを前提とします。

  • Spring Boot 3.x アプリのDockerイメージをレジストリにpush済み
  • kubectl でK8sクラスターにアクセスできる状態

作成するリソースはDeployment・Service・ConfigMap・Secretの4つです。

Spring Boot側の準備

K8sのProbeに対応するため、spring-boot-starter-actuator が依存関係に入っているか確認してください。

<!-- pom.xml -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
// build.gradle
implementation 'org.springframework.boot:spring-boot-starter-actuator'

Actuatorの基本的な使い方ははじめてのSpring Boot Actuator入門で解説しています。

次に application.yml でKubernetes向けのProbeエンドポイントを有効化します。

management:
  endpoint:
    health:
      probes:
        enabled: true
  endpoints:
    web:
      exposure:
        include: health

management.endpoint.health.probes.enabled=true を設定すると、/actuator/health/liveness/actuator/health/readiness が使えるようになります。なお、Spring Boot 3.xでは KUBERNETES_SERVICE_HOST 環境変数が設定されている場合(K8sクラスター上で実行中)はprobesが自動的に有効化されるため、この設定の明示は環境に応じて判断してもかまいません。

Deploymentマニフェストの作成

deployment.yaml を作成します。livenessProbeとreadinessProbeも一緒に設定してしまいましょう。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      # imagePullSecrets: [{name: regcred}]  # プライベートレジストリの場合は追加
      containers:
        - name: myapp
          image: your-registry/myapp:latest
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "250m"
              memory: "512Mi"
            limits:
              cpu: "500m"
              memory: "1Gi"
          envFrom:
            - configMapRef:
                name: myapp-config
            - secretRef:
                name: myapp-secret
          livenessProbe:
            httpGet:
              path: /actuator/health/liveness
              port: 8080
            initialDelaySeconds: 60
            periodSeconds: 10
          readinessProbe:
            httpGet:
              path: /actuator/health/readiness
              port: 8080
            initialDelaySeconds: 30
            periodSeconds: 5

livenessProbe はコンテナが「生きているか」を確認し、失敗するとPodが自動再起動されます。readinessProbe はトラフィックを受け付けられる状態かを確認し、失敗するとServiceのルーティング対象から外れます。

initialDelaySeconds はSpring Bootの起動時間に合わせて設定してください。短すぎるとアプリが起動しきる前にProbeが失敗してCrashLoopBackOffになります。起動に30秒かかるなら余裕を見て60秒程度が無難です。プライベートレジストリを使っている場合、imagePullSecrets のコメントアウトを外して認証情報を設定しないとImagePullBackOffになるので注意してください。

Serviceマニフェストの作成

apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  selector:
    app: myapp
  ports:
    - port: 80
      targetPort: 8080
  type: ClusterIP

type: ClusterIP はクラスター内部からのみアクセスできる設定で、デフォルトの推奨設定です。クラウド環境でインターネットに直接公開したい場合は LoadBalancer に変えると、クラウドプロバイダーのロードバランサーが作成されます。

ConfigMapで環境別プロパティを注入する

非機密の設定値はConfigMapで管理します。

apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-config
data:
  SPRING_PROFILES_ACTIVE: "production"
  APP_EXTERNAL_API_URL: "https://api.example.com"

SPRING_PROFILES_ACTIVE を環境変数として渡すことで、application-production.yml が自動的に読み込まれます。Profileや外部プロパティの詳細はSpring Bootのプロパティ設定ガイドSpring BootのProfileを使って環境別の設定を切り替える方法も参考にしてください。

SecretでDB接続情報を渡す

パスワードなど機密情報はSecretで管理します。

apiVersion: v1
kind: Secret
metadata:
  name: myapp-secret
type: Opaque
stringData:
  SPRING_DATASOURCE_URL: "jdbc:postgresql://db:5432/mydb"
  SPRING_DATASOURCE_USERNAME: "appuser"
  SPRING_DATASOURCE_PASSWORD: "your-secret-password"

stringData を使うと平文で記述できます。data フィールドを使う場合はBase64エンコードが必要です。

ひとつ重要な注意点があります。Kubernetes SecretはデフォルトではBase64エンコードされるだけで 暗号化はされません 。etcdにそのまま保存されるため、本番環境ではetcdの暗号化設定やExternal Secrets Operatorなどの外部シークレット管理ツールの導入を検討してください。ConfigMapとSecretの使い分けはシンプルで、外部に見せても問題ない設定はConfigMap、パスワードやAPIキーはSecretです。

kubectl applyで動作確認する

# 適用
kubectl apply -f configmap.yaml
kubectl apply -f secret.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# 状態確認
kubectl get pods
kubectl describe pod <pod-name>
kubectl logs <pod-name>

# ローカルからアクセス確認
kubectl port-forward svc/myapp 8080:80

kubectl get pods でSTATUSが Running、READYが 2/2(replicasが2の場合)になれば成功です。

ConfigMapやSecretを更新した後は Podの再起動 が必要です。envFrom で読み込んだ環境変数は起動時にしか取り込まれないため、kubectl rollout restart deployment/myapp で反映させましょう。

まとめ

Spring BootアプリをKubernetesにデプロイするときのポイントをまとめます。

  • management.endpoint.health.probes.enabled=true を設定する(K8s環境では KUBERNETES_SERVICE_HOST によって自動有効化される場合もある)
  • livenessProbeには /actuator/health/liveness、readinessProbeには /actuator/health/readiness を接続する
  • initialDelaySeconds はアプリの起動時間より余裕を持たせて設定する
  • 非機密設定はConfigMap、パスワード類はSecretで管理する
  • SecretはBase64エンコードのみで暗号化ではないため、本番環境では追加の対策が必要
  • ConfigMap/Secret更新後はPodの再起動が必要

HelmチャートやCI/CDパイプラインとの連携についてはまた別の機会に紹介します。