Working with Docker Deployment

1. Creating Dockerfile for Spring Boot

Example: Minimal Dockerfile with JRE

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY target/app.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]

2. Using Multi-Stage Builds

Example: Multi-stage Maven build

FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /src
COPY pom.xml .
RUN mvn -B -e -ntp dependency:go-offline
COPY src ./src
RUN mvn -B -e -ntp -DskipTests package

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=build /src/target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/app.jar"]

3. Building Docker Images (docker build)

Example: Build and tag Docker image

docker build -t myorg/orders:1.0 .
docker build --build-arg JAR=target/orders-1.0.jar -t myorg/orders:1.0 .

4. Running Containers (docker run)

Example: Run container with environment variables

docker run -d --name orders \
  -p 8080:8080 \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/orders \
  myorg/orders:1.0

5. Using Docker Compose (docker-compose.yml)

Example: Docker Compose with database health check

services:
  app:
    image: myorg/orders:1.0
    ports: ["8080:8080"]
    environment:
      SPRING_PROFILES_ACTIVE: prod
      SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/orders
    depends_on:
      db: { condition: service_healthy }
  db:
    image: postgres:16-alpine
    environment: { POSTGRES_PASSWORD: secret, POSTGRES_DB: orders }
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      retries: 10

6. Configuring Environment Variables

Property Env Var
spring.profiles.active SPRING_PROFILES_ACTIVE
spring.datasource.url SPRING_DATASOURCE_URL
server.port SERVER_PORT
Custom app.feature.x.enabled APP_FEATURE_X_ENABLED

7. Managing Container Volumes

Example: Bind mount config and log volume

services:
  app:
    image: myorg/orders:1.0
    volumes:
      - app-logs:/var/log/app
      - ./config:/config:ro
    environment:
      SPRING_CONFIG_ADDITIONAL_LOCATION: /config/
volumes:
  app-logs:

8. Using Layered JAR Structure (spring-boot-jarmode-layertools)

Example: Layered JAR Dockerfile

FROM eclipse-temurin:21-jre-alpine AS extract
WORKDIR /app
COPY target/app.jar app.jar
RUN java -Djarmode=layertools -jar app.jar extract

FROM eclipse-temurin:21-jre-alpine
WORKDIR /app
COPY --from=extract /app/dependencies/         ./
COPY --from=extract /app/spring-boot-loader/   ./
COPY --from=extract /app/snapshot-dependencies/ ./
COPY --from=extract /app/application/          ./
ENTRYPOINT ["java","org.springframework.boot.loader.launch.JarLauncher"]

9. Optimizing Image Size

Technique Effect
JRE base (not JDK) ~150MB savings
Alpine / distroless Minimal OS
Layered JAR Better layer caching
jlink custom JRE Tailored runtime
GraalVM native image ~80MB self-contained

10. Publishing Images to Registry

Example: Push image to container registry

docker login ghcr.io
docker tag myorg/orders:1.0 ghcr.io/myorg/orders:1.0
docker push ghcr.io/myorg/orders:1.0
# Or via Spring Boot buildpack
./mvnw spring-boot:build-image \
  -Dspring-boot.build-image.imageName=ghcr.io/myorg/orders:1.0 \
  -Dspring-boot.build-image.publish=true

11. Implementing Health Checks in Dockerfile

Example: Dockerfile health check for liveness probe

HEALTHCHECK --interval=30s --timeout=3s --start-period=20s --retries=3 \
  CMD wget --quiet --tries=1 --spider http://localhost:8080/actuator/health/liveness || exit 1