web

How to Dockerize a Spring Boot Application: A Complete Guide

hodaifa
Nov 30, 2025
5 min read

How to Dockerize a Spring Boot Application: A Complete Guide

Docker has become an essential tool for modern application deployment, offering consistency across different environments and simplifying the deployment process. In this comprehensive guide, we'll walk through dockerizing a Spring Boot application step by step.

Why Dockerize Your Spring Boot Application?

Before diving into the implementation, let's understand the benefits:

  • Consistency: Your application runs the same way in development, testing, and production
  • Isolation: Dependencies are contained within the Docker image
  • Scalability: Easy to scale horizontally with container orchestration
  • Portability: Deploy anywhere Docker is supported
  • Version Control: Docker images can be versioned and rolled back

Prerequisites

Before starting, make sure you have:

  • Java 17 or later installed
  • Maven or Gradle
  • Docker installed and running
  • Basic knowledge of Spring Boot

Step 1: Create a Simple Spring Boot Application

First, let's create a basic Spring Boot application. If you already have one, skip to Step 2.

Using Spring Initializr

  1. Go to start.spring.io
  2. Choose:
    • Project: Maven
    • Language: Java
    • Spring Boot: 3.2.0 (or latest stable)
    • Dependencies: Spring Web

Sample REST Controller

package com.example.demo.controller;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {
    
    @GetMapping("/")
    public String hello() {
        return "Hello from Dockerized Spring Boot!";
    }
    
    @GetMapping("/health")
    public String health() {
        return "Application is running!";
    }
}

Application Properties

# src/main/resources/application.properties
server.port=8080
spring.application.name=demo-app

Step 2: Create a Dockerfile

Create a file named Dockerfile in your project root:

Basic Dockerfile

FROM eclipse-temurin:17-jdk-alpine

WORKDIR /app

COPY target/*.jar app.jar

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

This approach builds the application inside Docker, resulting in a smaller final image:

# Stage 1: Build the application
FROM maven:3.9-eclipse-temurin-17 AS build

WORKDIR /app

# Copy pom.xml and download dependencies
COPY pom.xml .
RUN mvn dependency:go-offline

# Copy source code and build
COPY src ./src
RUN mvn clean package -DskipTests

# Stage 2: Create the runtime image
FROM eclipse-temurin:17-jre-alpine

WORKDIR /app

# Copy the jar from build stage
COPY --from=build /app/target/*.jar app.jar

# Create a non-root user
RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

EXPOSE 8080

ENTRYPOINT ["java", "-jar", "app.jar"]

Step 3: Create .dockerignore

Create a .dockerignore file to exclude unnecessary files:

target/
!target/*.jar
.git
.gitignore
README.md
*.md
.mvn/
mvnw
mvnw.cmd

Step 4: Build Your Docker Image

Build the Application (if using basic Dockerfile)

# Build with Maven
mvn clean package -DskipTests

# Build with Gradle
./gradlew build

Build the Docker Image

docker build -t spring-boot-app:latest .

For multi-platform builds:

docker buildx build --platform linux/amd64,linux/arm64 -t spring-boot-app:latest .

Step 5: Run Your Docker Container

Basic Run

docker run -p 8080:8080 spring-boot-app:latest

Run with Environment Variables

docker run -p 8080:8080 \
  -e SPRING_PROFILES_ACTIVE=prod \
  -e SERVER_PORT=8080 \
  spring-boot-app:latest

Run in Detached Mode

docker run -d \
  --name my-spring-app \
  -p 8080:8080 \
  --restart unless-stopped \
  spring-boot-app:latest

Create a docker-compose.yml file for easier management:

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: spring-boot-app
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - JAVA_OPTS=-Xmx512m -Xms256m
    restart: unless-stopped
    networks:
      - spring-network

networks:
  spring-network:
    driver: bridge

With Database (MySQL Example)

version: '3.8'

services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: spring-boot-app
    ports:
      - "8080:8080"
    environment:
      - SPRING_PROFILES_ACTIVE=prod
      - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/mydb
      - SPRING_DATASOURCE_USERNAME=root
      - SPRING_DATASOURCE_PASSWORD=rootpassword
    depends_on:
      mysql:
        condition: service_healthy
    restart: unless-stopped
    networks:
      - spring-network

  mysql:
    image: mysql:8.0
    container_name: spring-mysql
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: mydb
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - spring-network

volumes:
  mysql_data:

networks:
  spring-network:
    driver: bridge

Run with Docker Compose

# Start all services
docker-compose up -d

# View logs
docker-compose logs -f

# Stop all services
docker-compose down

# Stop and remove volumes
docker-compose down -v

Step 7: Optimize Your Docker Image

Use Layered Jars (Spring Boot 2.3+)

Update your pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <layers>
                    <enabled>true</enabled>
                </layers>
            </configuration>
        </plugin>
    </plugins>
</build>

Optimized Dockerfile with Layers

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

FROM eclipse-temurin:17-jre-alpine
WORKDIR /app

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

RUN addgroup -S spring && adduser -S spring -G spring
USER spring:spring

EXPOSE 8080

ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

Step 8: Push to Docker Registry

Docker Hub

# Login
docker login

# Tag your image
docker tag spring-boot-app:latest yourusername/spring-boot-app:latest

# Push
docker push yourusername/spring-boot-app:latest

Private Registry

# Tag with registry URL
docker tag spring-boot-app:latest registry.example.com/spring-boot-app:latest

# Push
docker push registry.example.com/spring-boot-app:latest

Step 9: Deploy to Production

Using Docker

# Pull latest image
docker pull yourusername/spring-boot-app:latest

# Run container
docker run -d \
  --name spring-app \
  -p 80:8080 \
  --restart unless-stopped \
  yourusername/spring-boot-app:latest

Using Docker Compose in Production

# Pull and start services
docker-compose -f docker-compose.prod.yml up -d

# View logs
docker-compose -f docker-compose.prod.yml logs -f app

Best Practices

  1. Use Multi-Stage Builds: Reduces final image size significantly
  2. Don't Run as Root: Create a non-root user for security
  3. Use Specific Base Image Tags: Avoid latest tag in production
  4. Implement Health Checks: Add Spring Boot Actuator for monitoring
  5. Use Environment Variables: Never hardcode sensitive information
  6. Optimize Layers: Order Dockerfile commands from least to most frequently changing
  7. Use .dockerignore: Exclude unnecessary files from build context
  8. Version Your Images: Use semantic versioning for Docker images

Adding Spring Boot Actuator

Add to pom.xml:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

Update application.properties:

management.endpoints.web.exposure.include=health,info,metrics
management.endpoint.health.show-details=always

Update Dockerfile with health check:

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

Troubleshooting

Container Exits Immediately

# Check logs
docker logs spring-boot-app

# Run interactively
docker run -it spring-boot-app:latest /bin/sh

Connection Refused

  • Ensure the application binds to 0.0.0.0, not localhost
  • Check port mappings: -p host:container
  • Verify firewall rules

Out of Memory

# Increase memory limit
docker run -m 1g spring-boot-app:latest

# Or set Java heap size
docker run -e JAVA_OPTS="-Xmx512m -Xms256m" spring-boot-app:latest

Conclusion

You've successfully dockerized your Spring Boot application! This setup provides a solid foundation for deploying your application in any environment that supports Docker.