Dockerizing & Deploying Spring Boot

🌿 Spring BootLesson 15Advanced

The final step is getting your Spring Boot application into production. This lesson covers building optimized Docker images with layered JARs, deploying with Docker Compose, and publishing to cloud platforms.

1 Layered JAR Dockerfile
Dockerfile — Optimized Multi-Stage Build
# Stage 1: Extract layers from the Spring Boot fat JAR
FROM eclipse-temurin:21-jre-alpine AS builder
WORKDIR /app
COPY target/*.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract

# Stage 2: Final minimal image
FROM eclipse-temurin:21-jre-alpine

# Security: run as non-root
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

WORKDIR /app

# Copy layers in order of least-to-most frequently changing
# (maximizes Docker cache reuse)
COPY --from=builder /app/dependencies/           ./
COPY --from=builder /app/spring-boot-loader/     ./
COPY --from=builder /app/snapshot-dependencies/  ./
COPY --from=builder /app/application/            ./

EXPOSE 8080

HEALTHCHECK --interval=30s --timeout=3s \
  CMD wget -qO- http://localhost:8080/actuator/health || exit 1

ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
2 Docker Compose
YAML — docker-compose.yml
version: "3.9"
services:
  api:
    build: .
    ports: ["8080:8080"]
    environment:
      SPRING_PROFILES_ACTIVE: prod
      SPRING_DATASOURCE_URL: jdbc:postgresql://postgres:5432/mydb
      SPRING_DATASOURCE_USERNAME: postgres
      SPRING_DATASOURCE_PASSWORD: ${DB_PASSWORD}
      APP_SECURITY_JWT_SECRET: ${JWT_SECRET}
    depends_on:
      postgres:
        condition: service_healthy
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pg_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

volumes:
  pg_data:
3 Build & Run Commands
Shell — Build & Deploy
# Build JAR
mvn clean package -DskipTests

# Build Docker image
docker build -t my-api:1.0.0 .

# Run with Docker Compose
docker-compose up -d

# View logs
docker-compose logs -f api

# Spring Boot Buildpacks (no Dockerfile needed!)
mvn spring-boot:build-image -Dspring-boot.build-image.imageName=my-api:1.0.0
4 Code Challenge
Challenge: Dockerize your Spring Boot application with the layered JAR Dockerfile. Write a docker-compose.yml with the API, PostgreSQL, and a Redis container. Deploy to Railway.app using their GitHub integration and verify the /actuator/health endpoint returns UP.