Docker Multi-Stage Builds & Production Kubernetes Deployment Guide

Deploying microservices to production requires minimal container images, zero-downtime rolling updates, and self-healing cluster orchestration. Learn how to write multi-stage Dockerfiles that reduce image sizes from 850MB to 45MB, and configure Kubernetes Horizontal Pod Autoscalers (HPA).

1. Production Multi-Stage Dockerfile for Spring Boot / Java 21

# Stage 1: Build & Package Application
FROM eclipse-temurin:21-jdk-alpine AS builder
WORKDIR /app
COPY .mvn/ .mvn
COPY mvnw pom.xml ./
RUN ./mvnw dependency:go-offline
COPY src ./src
RUN ./mvnw package -DskipTests

# Stage 2: Minimal Distroless Production Runtime Container
FROM eclipse-temurin:21-jre-alpine AS runner
WORKDIR /app
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
COPY --from=builder /app/target/*.jar app.jar

EXPOSE 8080
ENTRYPOINT ["java", "-XX:+UseG1GC", "-XX:MaxRAMPercentage=75.0", "-jar", "app.jar"]

2. Kubernetes Deployment Spec with Health Probes & Resource Limits

apiVersion: apps/v1
kind: Deployment
metadata:
  name: backend-api
  labels:
    app: backend-api
spec:
  replicas: 3
  selector:
    matchLabels:
      app: backend-api
  template:
    metadata:
      labels:
        app: backend-api
    spec:
      containers:
      - name: api
        image: registry.company.com/backend-api:v2.4.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
        livenessProbe:
          httpGet:
            path: /actuator/health/liveness
            port: 8080
          initialDelaySeconds: 20
          periodSeconds: 10
        readinessProbe:
          httpGet:
            path: /actuator/health/readiness
            port: 8080
          initialDelaySeconds: 15
          periodSeconds: 5

3. Kubernetes Horizontal Pod Autoscaler (HPA v2) Manifest

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: backend-api-hpa
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: backend-api
  minReplicas: 3
  maxReplicas: 20
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 75
  - type: Resource
    resource:
      name: memory
      target:
        type: Utilization
        averageUtilization: 80

4. Helm Chart Chart.yaml & Values.yaml Strategy

# Chart.yaml
apiVersion: v2
name: backend-service
version: 1.0.0
appVersion: "2.4.0"
description: Production Helm chart for microservice deployments

# values.yaml
replicaCount: 3
image:
  repository: registry.company.com/backend-api
  pullPolicy: IfNotPresent
  tag: "v2.4.0"

service:
  type: ClusterIP
  port: 8080

ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: "letsencrypt-prod"
  hosts:
    - host: api.company.com
      paths:
        - path: /
          pathType: Prefix

5. Related DevOps Resources

6. Frequently Asked Questions (FAQ)

Why use multi-stage Docker builds in production?
Multi-stage builds separate the build environment (compilers, SDKs, build tools) from the runtime environment. This reduces container image size by up to 90% (e.g. 850MB β†’ 45MB) and dramatically shrinks the attack surface by excluding unnecessary binaries.
What is the difference between Liveness and Readiness probes in Kubernetes?
A Liveness Probe checks if the application container is alive. If it fails, Kubernetes kills and restarts the container. A Readiness Probe checks if the app is ready to accept HTTP traffic. If it fails, K8s removes the Pod from the Service load balancer without killing it.

πŸ“š Related Technical Guides

πŸ‘¨β€πŸ’»

Nagendra Rana

Software Development Engineer 2 (SDE-2) @ Digilytics AI & Founder of WhatInfoTech

Architecting scalable enterprise Angular applications, Spring Boot 3 microservices, Python / FastAPI, PostgreSQL, and AI document extraction solutions.

β˜• Support My Work