Course topics

By WebNest Studio

Spring Boot Tutorial

Deploying Spring Boot to Kubernetes

Kubernetes has become the standard platform for running containerised services: it schedules containers onto machines, restarts failed instances, scales on load, rolls out new versions without downtime, and manages configuration and secrets. Spring Boot is designed to work well there — health probes, graceful shutdown, externalised configuration and metrics all map directly onto Kubernetes features.

This lesson deploys a Spring Boot application with a Deployment, Service, ConfigMap and Secret, configures probes, resources and graceful shutdown for zero-downtime rollouts, adds autoscaling, and explains the settings that most often cause trouble.

The Core Objects

A Deployment declares how many replicas of your container to run and how to update them. A Service gives the pods a stable name and load-balances between them; an Ingress or Gateway exposes it outside the cluster. A ConfigMap holds non-secret configuration and a Secret holds credentials; both can be provided as environment variables or files that Spring Boot reads.

Configuration from ConfigMaps and Secrets

Environment variables map to properties through relaxed binding (SPRING_DATASOURCE_URL). For many settings, mount a ConfigMap as files and import them with spring.config.import=configtree:/etc/config/, where each file name becomes a property. Spring Cloud Kubernetes can also read ConfigMaps directly, but plain environment variables and config trees are usually enough.

Probes, Resources and Shutdown

Point the livenessProbe at /actuator/health/liveness and the readinessProbe at /actuator/health/readiness, with a startupProbe so slow startups are not killed. Set CPU and memory requests and limits; the JVM respects container memory limits, so size the heap with -XX:MaxRAMPercentage. For zero-downtime rollouts, Spring Boot's graceful shutdown and readiness state handle in-flight requests, and a short preStop sleep gives load balancers time to stop sending traffic before the app shuts down.

Scaling

A HorizontalPodAutoscaler adds or removes replicas based on CPU or custom metrics (for example request rate from Prometheus). Because every replica runs its own scheduler, caches and connection pools, remember the multi-instance concerns covered earlier: ShedLock for scheduled jobs, Redis for shared caches and sessions, and database pool sizes multiplied by replica count.

Examples

Deployment with probes, resources, config and graceful shutdown

Java
apiVersion: apps/v1
kind: Deployment
metadata:
  name: webnest-shop
spec:
  replicas: 3
  selector:
    matchLabels: { app: webnest-shop }
  strategy:
    rollingUpdate: { maxUnavailable: 0, maxSurge: 1 }
  template:
    metadata:
      labels: { app: webnest-shop }
    spec:
      terminationGracePeriodSeconds: 45
      containers:
        - name: app
          image: ghcr.io/webnest/shop:1.0.0
          ports:
            - containerPort: 8080
          env:
            - name: SPRING_PROFILES_ACTIVE
              value: prod
            - name: JAVA_TOOL_OPTIONS
              value: "-XX:MaxRAMPercentage=75"
            - name: SPRING_DATASOURCE_PASSWORD
              valueFrom:
                secretKeyRef: { name: shop-db, key: password }
          envFrom:
            - configMapRef: { name: shop-config }
          resources:
            requests: { cpu: 500m, memory: 768Mi }
            limits:   { memory: 768Mi }
          startupProbe:
            httpGet: { path: /actuator/health/liveness, port: 8080 }
            failureThreshold: 30
            periodSeconds: 2
          livenessProbe:
            httpGet: { path: /actuator/health/liveness, port: 8080 }
            periodSeconds: 10
          readinessProbe:
            httpGet: { path: /actuator/health/readiness, port: 8080 }
            periodSeconds: 5
          lifecycle:
            preStop:
              sleep: { seconds: 10 }      # let load balancers remove the pod first
Output
kubectl apply -f deployment.yaml
deployment.apps/webnest-shop created
kubectl get pods
webnest-shop-7d9c6b5f4-2xkqp   1/1   Running   0   42s
webnest-shop-7d9c6b5f4-8mzvn   1/1   Running   0   42s
webnest-shop-7d9c6b5f4-tq4rw   1/1   Running   0   42s

ConfigMap, Secret, Service and Ingress

Java
apiVersion: v1
kind: ConfigMap
metadata:
  name: shop-config
data:
  SPRING_DATASOURCE_URL: jdbc:postgresql://postgres.db.svc.cluster.local:5432/webnest
  SPRING_DATASOURCE_USERNAME: webnest
  LOGGING_STRUCTURED_FORMAT_CONSOLE: ecs
---
apiVersion: v1
kind: Secret
metadata:
  name: shop-db
type: Opaque
stringData:
  password: change-me          # in practice created by a secret manager / sealed secrets
---
apiVersion: v1
kind: Service
metadata:
  name: webnest-shop
spec:
  selector: { app: webnest-shop }
  ports:
    - port: 80
      targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: webnest-shop
spec:
  rules:
    - host: shop.webneststudio.co.in
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service: { name: webnest-shop, port: { number: 80 } }
Output
curl https://shop.webneststudio.co.in/actuator/health/readiness
{"status":"UP"}

Rolling update, rollback and autoscaling

Java
# Deploy a new version with zero downtime
kubectl set image deployment/webnest-shop app=ghcr.io/webnest/shop:1.1.0
kubectl rollout status deployment/webnest-shop

# Something wrong? Roll back
kubectl rollout undo deployment/webnest-shop

# Scale on CPU between 3 and 10 replicas
kubectl autoscale deployment webnest-shop --cpu-percent=70 --min=3 --max=10
Output
Waiting for deployment "webnest-shop" rollout to finish: 1 of 3 updated replicas are available...
deployment "webnest-shop" successfully rolled out
horizontalpodautoscaler.autoscaling/webnest-shop autoscaled

Common Mistakes

  • Using the database health check in the liveness probe, causing restart storms during database incidents.
  • No startupProbe for a slow-starting app, so the liveness probe kills it before it finishes starting.
  • Setting a memory limit but letting the JVM heap use all of it, leaving no room for metaspace and threads (OOMKilled).
  • terminationGracePeriodSeconds shorter than Spring's shutdown timeout, cutting off in-flight requests.
  • Storing secrets in ConfigMaps or committing Secret manifests with real passwords to Git.

Key Points to Remember

  • Deployment + Service + Ingress run and expose the app; ConfigMaps and Secrets configure it.
  • Liveness, readiness and startup probes map to Spring Boot's health groups.
  • Set resources and MaxRAMPercentage so the JVM fits the container.
  • Graceful shutdown + readiness + preStop give zero-downtime rolling updates.
  • Autoscale with HPA and handle multi-instance concerns (locks, shared caches, pool sizes).

Practice the examples

Change an input, predict the result, then compare it with the output. Explain why the result changes.

Use your local JDK or project IDE for these examples. Codelab currently runs Python and HTML/CSS/JavaScript; framework examples may need project dependencies.