DEV Community

Cover image for DevOps: Dockerizing Your Spring Boot App
Harshit Singh
Harshit Singh

Posted on

DevOps: Dockerizing Your Spring Boot App

Introduction: Ship Faster, Scale Smarter

What if you could deploy your app across any environment in minutes, without the dreaded “it works on my machine” excuse? In 2023, 75% of enterprises adopted Docker to streamline deployments, slashing setup time by up to 60%. Dockerizing your Spring Boot app is a cornerstone of modern DevOps, enabling consistent, portable, and scalable applications. Whether you're a beginner deploying your first Java app or a seasoned DevOps engineer optimizing CI/CD pipelines, mastering Docker with Spring Boot is your ticket to faster releases and a standout career.

Docker packages apps into containers, ensuring they run identically everywhere, while Spring Boot simplifies Java development with embedded servers. This guide follows a developer’s journey from deployment nightmares to DevOps mastery, covering core concepts, practical steps, and advanced techniques. With Java code, Dockerfiles, a flow chart, case studies, and a dash of humor, this article is your ultimate resource to dockerize like a pro. Let’s containerize and conquer!


The Story: From Deployment Disasters to Docker Triumphs

Meet Priya, a Java developer at a retail startup. Her team’s Spring Boot app crashed in production due to environment mismatches, costing hours of debugging. Frustrated, Priya discovered Docker, containerizing the app to ensure consistency across dev, test, and prod. Deployments became seamless, and the team scaled to handle Black Friday traffic. This problem-solution arc mirrors Docker’s rise since 2013, transforming DevOps by standardizing deployments. Let’s dive into how you can dockerize your Spring Boot app and avoid Priya’s pain.


Section 1: What Is Dockerizing a Spring Boot App?

Defining Docker and Spring Boot

Docker is a platform that packages applications into containers—lightweight, portable units with code, dependencies, and runtime. Spring Boot is a Java framework for building production-ready apps with minimal configuration, often using an embedded Tomcat server.

Dockerizing a Spring Boot app means packaging it into a Docker container, ensuring it runs consistently across environments (dev, staging, production).

Analogy: Docker is like a lunchbox—your Spring Boot app (the sandwich) and its dependencies (condiments) are packed together, ready to go anywhere without spilling.

Why Dockerize Your Spring Boot App?

  • Consistency: Eliminate environment-specific bugs.
  • Portability: Run on any system with Docker installed.
  • Scalability: Deploy multiple containers to handle load.
  • DevOps Efficiency: Streamline CI/CD pipelines.
  • Career Boost: Docker skills are in high demand.

Common Misconception

Myth: Docker is too complex for small projects.

Truth: Docker simplifies even small apps by ensuring consistent setups.

Takeaway: Dockerizing Spring Boot apps ensures consistency and scalability, making it accessible for projects of all sizes.


Section 2: Getting Started with Docker and Spring Boot

Prerequisites

  • Java 17+: For Spring Boot.
  • Maven: For building the app.
  • Docker: Installed locally (Docker Desktop for Windows/Mac).
  • Spring Boot Project: A basic app (e.g., REST API).

Creating a Simple Spring Boot App

Let’s build a REST API to dockerize.

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
</project>
Enter fullscreen mode Exit fullscreen mode

RestController:

package com.example.demo;

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

@RestController
public class HelloController {
    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, Dockerized Spring Boot!";
    }
}
Enter fullscreen mode Exit fullscreen mode

Application:

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Setup: A minimal Spring Boot app with a /hello endpoint.
  • Purpose: Returns a greeting, testable locally (http://localhost:8080/hello).
  • Real-World Use: Basis for APIs in e-commerce or microservices.

Dockerizing the App

Create a Dockerfile to containerize the app.

Dockerfile:

# Use official OpenJDK 17 base image
FROM openjdk:17-jdk-slim

# Set working directory
WORKDIR /app

# Copy Maven-built JAR file
COPY target/demo-0.0.1-SNAPSHOT.jar app.jar

# Expose port 8080
EXPOSE 8080

# Run the JAR file
ENTRYPOINT ["java", "-jar", "app.jar"]
Enter fullscreen mode Exit fullscreen mode

Steps to Dockerize:

  1. Build the app: mvn clean package
  2. Build the Docker image: docker build -t demo-app .
  3. Run the container: docker run -p 8080:8080 demo-app

Explanation:

  • Dockerfile: Uses OpenJDK 17, copies the JAR, exposes port 8080, and runs the app.
  • Commands: Build the JAR, create an image, and run it as a container.
  • Real-World Use: Deploys a Spring Boot API in a consistent environment.

Takeaway: Create a simple Spring Boot app and dockerize it with a basic Dockerfile to ensure portability.


Section 3: Core Docker Concepts for Spring Boot

Images and Containers

  • Image: A blueprint with app code, dependencies, and runtime (e.g., demo-app).
  • Container: A running instance of an image, isolated and lightweight.

Dockerfile Best Practices

  • Minimize Layers: Combine commands (e.g., RUN apt-get update && apt-get install).
  • Use Slim Base Images: openjdk:17-jdk-slim reduces size.
  • Leverage .dockerignore: Exclude unnecessary files (e.g., target/).

.dockerignore:

target/
*.log
.git/
Enter fullscreen mode Exit fullscreen mode

Multi-Stage Builds

Reduce image size by building and running in separate stages.

Dockerfile (Multi-Stage):

# Build stage
FROM maven:3.8.6-openjdk-17 AS builder
WORKDIR /build
COPY pom.xml .
COPY src ./src
RUN mvn clean package -DskipTests

# Run stage
FROM openjdk:17-jdk-slim
WORKDIR /app
COPY --from=builder /build/target/demo-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Enter fullscreen mode Exit fullscreen mode

Explanation: Builds the JAR in a Maven stage, then copies only the JAR to a slim runtime image, reducing size by 50%.

Humor: A bloated Docker image is like packing a suitcase with bricks—lighten up with multi-stage builds! 😄

Takeaway: Use slim images, .dockerignore, and multi-stage builds to create efficient Docker images for Spring Boot apps.


Section 4: Deploying with Docker Compose

What Is Docker Compose?

Docker Compose manages multi-container apps (e.g., Spring Boot + database) using a YAML file.

Example: Spring Boot with PostgreSQL

docker-compose.yml:

version: '3.8'
services:
  app:
    image: demo-app
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8080:8080"
    environment:
      - SPRING_DATASOURCE_URL=jdbc:postgresql://db:5432/demo
      - SPRING_DATASOURCE_USERNAME=postgres
      - SPRING_DATASOURCE_PASSWORD=postgres
    depends_on:
      - db
  db:
    image: postgres:15
    environment:
      - POSTGRES_DB=demo
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    ports:
      - "5432:5432"
    volumes:
      - db-data:/var/lib/postgresql/data
volumes:
  db-data:
Enter fullscreen mode Exit fullscreen mode

Updated Spring Boot Config (application.properties):

spring.datasource.url=jdbc:postgresql://db:5432/demo
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.jpa.hibernate.ddl-auto=update
Enter fullscreen mode Exit fullscreen mode

Steps:

  1. Run: docker-compose up -d
  2. Access: http://localhost:8080/hello
  3. Stop: docker-compose down

Explanation:

  • Compose File: Defines an app service (Spring Boot) and a db service (PostgreSQL), linking them via environment variables.
  • Networking: Docker Compose creates a default network for service communication (e.g., db:5432).
  • Real-World Use: Runs a full-stack app with database in development or staging.

Flow Chart: Docker Compose Workflow

Image description

Explanation: This flow chart illustrates the Docker Compose process, from defining services to running and stopping containers, clarifying the workflow for beginners and experts.

Takeaway: Use Docker Compose to manage multi-container Spring Boot apps with databases for seamless development and testing.


Section 5: Comparing Docker with Alternatives

Table: Docker vs. Podman vs. Kubernetes

Feature Docker Podman Kubernetes
Type Container platform Container engine Orchestration platform
Ease of Use High (simple CLI, Compose) Moderate (Docker-compatible) Low (complex setup)
Use Case Development, single containers Rootless containers, security Production, multi-container orchestration
Scalability Moderate (Compose for small apps) Moderate (similar to Docker) High (auto-scaling, load balancing)
Community Large, mature Growing, open-source Large, enterprise-focused
Spring Boot Fit Excellent (easy dockerization) Good (Dockerfile compatible) Advanced (for microservices)

Explanation: Docker is ideal for dockerizing Spring Boot apps, Podman suits security-focused environments, and Kubernetes excels in production orchestration. This table helps choose the right tool.

Takeaway: Use Docker for Spring Boot dockerization, Podman for rootless setups, or Kubernetes for production scaling.


Section 6: Real-Life Case Study

Case Study: Scaling an E-Commerce Platform

An e-commerce company struggled with inconsistent deployments across dev, test, and prod, causing delays. They dockerized their Spring Boot app:

  • Implementation: Used a multi-stage Dockerfile and Docker Compose with PostgreSQL, integrated with Jenkins for CI/CD.
  • Configuration: Deployed 10 containers behind a load balancer to handle peak traffic.
  • Result: Deployment time dropped from 2 hours to 10 minutes, and the app handled 1 million users during sales with 99.9% uptime.
  • Lesson: Docker ensures consistency and scales under pressure.

Takeaway: Dockerize Spring Boot apps with Compose and CI/CD for fast, reliable deployments.


Section 7: Advanced Docker Techniques

Optimizing Image Size

  • Use JRE Instead of JDK: Replace openjdk:17-jdk-slim with openjdk:17-jre-slim.
  • Remove Unnecessary Files: Clean up in the Dockerfile (e.g., RUN rm -rf /tmp/*).

Example:

FROM openjdk:17-jre-slim
WORKDIR /app
COPY target/demo-0.0.1-SNAPSHOT.jar app.jar
RUN rm -rf /tmp/*
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
Enter fullscreen mode Exit fullscreen mode

Health Checks

Add health checks to monitor container status.

Dockerfile:

HEALTHCHECK --interval=30s --timeout=3s \
  CMD curl -f http://localhost:8080/actuator/health || exit 1
Enter fullscreen mode Exit fullscreen mode

application.properties:

management.endpoints.web.exposure.include=health
Enter fullscreen mode Exit fullscreen mode

Docker in CI/CD with Jenkins

Jenkins Pipeline:

pipeline {
    agent any
    stages {
        stage('Build') {
            steps {
                sh 'mvn clean package'
            }
        }
        stage('Docker Build') {
            steps {
                sh 'docker build -t demo-app .'
            }
        }
        stage('Deploy') {
            steps {
                sh 'docker run -d -p 8080:8080 demo-app'
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Explanation:

  • Health Checks: Ensure the app is running via Spring Boot Actuator.
  • CI/CD: Automates building, dockerizing, and deploying the app.
  • Real-World Use: Streamlines production deployments.

Takeaway: Optimize images, add health checks, and integrate with CI/CD for production-ready Dockerized apps.


Section 8: Common Pitfalls and Solutions

Pitfall 1: Large Image Sizes

Risk: Slow builds and deployments.

Solution: Use multi-stage builds and JRE-based images.

Pitfall 2: Environment Misconfigurations

Risk: App fails due to missing variables.

Solution: Use Docker Compose environment variables and validate configs.

Pitfall 3: Ignoring Security

Risk: Vulnerabilities in images.

Solution: Scan images with docker scan and use trusted base images.

Humor: An unoptimized Docker image is like a suitcase full of rocks—hard to carry and nobody’s impressed! 😅

Takeaway: Optimize images, configure environments correctly, and prioritize security to dockerize effectively.


Section 9: FAQ

Q: Do I need Docker for local development?

A: Docker simplifies local setups by mimicking production, but it’s optional for small apps.

Q: How do I debug a Dockerized Spring Boot app?

A: Use docker logs or attach a debugger with JAVA_TOOL_OPTIONS.

Q: Can I dockerize without Spring Boot?

A: Yes, but Spring Boot’s embedded server simplifies the process.

Takeaway: Use the FAQ to address doubts and build confidence in dockerizing Spring Boot apps.


Section 10: Quick Reference Checklist

  • [ ] Create a Spring Boot app with Maven.
  • [ ] Write a Dockerfile using a slim base image.
  • [ ] Use .dockerignore to exclude unnecessary files.
  • [ ] Implement multi-stage builds for smaller images.
  • [ ] Set up Docker Compose for multi-container apps.
  • [ ] Add health health checks for monitoring.
  • [ ] Integrate with CI/CD for automated deployments.
  • [ ] Scan images for security vulnerabilities.

Takeaway: Keep this checklist for your next Dockerized Spring Boot project to ensure success.


Conclusion: Master Docker for Spring Boot Success

Dockerizing your Spring Boot app unlocks consistent, portable, and scalable deployments, revolutionizing your DevOps workflow. From simple Dockerfiles to multi-container Compose setups and CI/CD integration, Docker empowers you to ship faster and scale smarter. Whether you’re a beginner or a DevOps pro, these techniques will elevate your projects and career.

Call to Action: Start dockerizing today! Build the Spring Boot app above, create a Dockerfile, or try Docker Compose with a database. Share your Docker journey on Dev.to, r/java, or the Docker Community forums to connect with others.

Additional Resources

  • Books:
    • Docker in Action by Jeff Nickoloff
    • Spring Boot in Practice by Somnath Musib
  • Tools:
    • Docker Desktop: Local Docker environment (Pros: User-friendly; Cons: Resource-heavy).
    • Portainer: Container management UI (Pros: Intuitive; Cons: Limited advanced features).
    • Jenkins: CI/CD automation (Pros: Flexible; Cons: Setup complexity).
  • Communities: r/docker, Stack Overflow, Spring Community forums

Glossary

  • Docker: Platform for containerizing applications.
  • Container: Lightweight, portable app instance.
  • Dockerfile: Script defining a Docker image.
  • Docker Compose: Tool for multi-container apps.
  • Spring Boot: Java framework with embedded server.

Top comments (0)