Docker and Java: Application Containerization for Developers

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 to Docker and Java



Modern Java application development is unthinkable without containerization. Docker is a platform for packaging, delivering, and running applications in isolated environments (containers). For Java developers, Docker solves the eternal problem: "It works on my machine!". A container guarantees that your application will run identically on your local machine, development server, and in production.



In this article, we will explore how to containerize Java applications using Docker: from a simple Dockerfile to optimizing images for microservice architecture. All examples are written in Java and ready to use.



Docker Basics for Java Applications



What is a Docker Image and Container?

A Docker image is a template (read-only) containing everything needed to run an application: JVM, libraries, code, and configurations. A container is a running instance of an image. For Java, this means you don't need to manually install JDK on the server — the JVM will already be inside the container.



Creating a Simple Dockerfile for Java

Let's look at a basic example. We have a simple Java application (e.g., HelloWorld.java).



// HelloWorld.javapublic class HelloWorld {    public static void main(String[] args) {        System.out.println("Hello from Docker and Java!");    }}


Let's create a Dockerfile:



# Use the official OpenJDK imageFROM openjdk:11-jre-slim

# Set the working directoryWORKDIR /app

# Copy the compiled jar or class filesCOPY HelloWorld.class .

# Run commandCMD ["java", "HelloWorld"]


Building and running:



# Build the imagedocker build -t hello-java .

# Run the containerdocker run hello-java


Output: Hello from Docker and Java!



Containerizing Spring Boot Applications



For real projects (e.g., Spring Boot), the process becomes more complex. Let's look at a typical microservice.



Multi-stage Build

This is a best practice for Java: first build the application with the full JDK, then copy the result into a lightweight JRE image.



# Stage 1: BuildFROM maven:3.8.5-openjdk-11 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn clean package -DskipTests

# Stage 2: RunFROM openjdk:11-jre-slimWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]


Explanation:

  • build — uses Maven and the full JDK for compilation.
  • Final image — contains only JRE and the ready jar file. The image size is reduced by 2-3 times.


Optimizing Layer Caching

Docker caches each layer (instruction). To speed up builds, place rarely changed dependencies at the beginning:



FROM maven:3.8.5-openjdk-11 AS buildWORKDIR /app# Cache dependenciesCOPY pom.xml .RUN mvn dependency:go-offline# Now copy the codeCOPY src ./srcRUN mvn clean package


Now, if you only change the code, Docker will only rebuild the last layers, while dependencies will be taken from the cache.



Working with Environment Variables and Profiles



Passing Parameters to a Java Application

Docker allows you to flexibly configure your application through environment variables. This is especially convenient for Spring Boot.



docker run -e SPRING_PROFILES_ACTIVE=prod -e DB_URL=jdbc:postgresql://db:5432/mydb my-app


In the Dockerfile, you can set default values:



ENV SPRING_PROFILES_ACTIVE=devENV DB_URL=jdbc:h2:mem:testdb


Example docker-compose for Java + Database

For microservices, it's convenient to use docker-compose.yml:



version: '3.8'services:  app:    bu                

Blogs

Book Recommendations