Docker and Java: Containerizing Applications from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Docker is Important for a Java Developer?



Modern Java development rarely goes without containerization. Docker allows you to package an application together with all its dependencies, JVM, and configuration into an isolated container. This solves the "it works on my machine" problem and simplifies CI/CD. In this article, we will cover the full cycle: from installing Docker to optimizing images for production.



1. Docker Basics for Java



1.1 What is Docker and Why Does It Matter for Java Projects?



Docker is a platform for creating, delivering, and running applications in containers. This is especially relevant for Java:

  • JVM version isolation — you can use Java 11 for one service and Java 17 for another on the same host.
  • Reproducibility — the image contains the exact version of the JDK, libraries, and system utilities.
  • Scalability — easily run multiple instances via Kubernetes or Docker Swarm.


1.2 Installing Docker



To start, install Docker Desktop (Windows/Mac) or Docker Engine (Linux). Verify the installation:



docker --versiondocker info


2. Creating a Dockerfile for a Java Application



Let's consider a simple Spring Boot application. Create a Dockerfile in the project root.



2.1 Basic Dockerfile



# Use the official OpenJDK imageFROM openjdk:17-jdk-alpine

# Set the working directoryWORKDIR /app

# Copy the JAR fileCOPY target/myapp.jar app.jar

# Expose the portEXPOSE 8080

# Startup commandENTRYPOINT ["java", "-jar", "app.jar"]


2.2 Building and Running the Container



# Build the imagedocker build -t my-java-app .

# Run the containerdocker run -p 8080:8080 my-java-app


After running, the application will be available at http://localhost:8080.



3. Optimizing Docker Images for Java



Large images slow down deployment. Let's look at key optimization techniques.



3.1 Multi-stage Builds



This allows separating the build stage from the runtime stage. Only the JAR ends up in the final image, without Maven/Gradle and source code.



# Build stageFROM maven:3.8.5-openjdk-17 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn package -DskipTests

# Runtime stageFROM openjdk:17-jdk-alpineWORKDIR /appCOPY --from=build /app/target/myapp.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]


3.2 Layer Optimization



Docker caches layers. Separate data copying: first dependencies (change rarely), then code (changes frequently).



FROM maven:3.8.5-openjdk-17 AS buildWORKDIR /app# Copy only POM and download dependenciesCOPY pom.xml .RUN mvn dependency:go-offline# Copy sources and buildCOPY src ./srcRUN mvn package -DskipTests

FROM openjdk:17-jdk-alpineWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]


3.3 Using jlink to Create a Minimal JRE



If you are using Java 9+, you can create a custom JRE with only the required modules.



FROM openjdk:17-slim AS jre-buildRUN jlink --add-modules java.base,java.logging,java.sql \          --output /jre \          --strip-debug \          --no-man-pages \          --no-header-files

FROM alpine:latestCOPY --from=jre-build /jre /jreCOPY target/app.jar /app.jarENTRYPOINT ["/jre/bin/java", "-jar", "/app.jar"]


Such an image can weigh less than 50 MB instead of 300+ MB.



4. Docker Compose for Java Microservices



If you have multiple services (e.g., Spring Boot + PostgreSQL), use docker-compose.yml.



4.1 Pr

Blogs

Book Recommendations