Dockerizing Spring Boot Application: Adhering to 8 Best Practices

Pratiyush Prakash
Dev Genius
Published in
4 min readMar 11, 2024

--

Docker plays a pivotal role in modern software development, and Spring Boot applications are no strangers to its influence. Now, the classic excuse, “it works on my machine” has a new friend: Docker. By adhering to best practices, you can ensure a smooth and efficient Dockerization process for your Spring Boot application. In this article we’ll explore best practices, offering examples to guide you through Dockerizing your Spring Boot application.

Photo by Ian Taylor on Unsplash

This time around, we’ll switch things up — we’ll kick off with the practical implementation and then circle back to cover the theory. This approach allows us to relate the theory directly to the example as we go through it.

We have a standard spring boot application, and now, we’re going to dockerize it while sticking to the best practices.

Dockerizing Spring Boot Application

# Stage 1: Build Step
FROM maven:3.8.4-openjdk-11-slim AS build
WORKDIR /app

# Copy only the POM file to cache dependency
COPY pom.xml .
RUN mvn dependency:go-offline

# Copy the rest of the application source code and build
COPY src src
RUN mvn clean package -DskipTests

# Stage 2: Final Steps
FROM openjdk:11.0.12-jre-slim
WORKDIR /app

# Create a non-root user for running the application
RUN adduser --disabled-password --gecos '' springuser
USER springuser

# Copy the WAR file from build stage
ARG VERSION=0.0.1
COPY --from=build /app/target/demo-${VERSION}-SNAPSHOT.war app.war

# Expose the application port
EXPOSE 8080

# Running command, specify resource constraints
CMD ["java", "-Xmx256m", "-jar", "app.war"]
HELP.md
target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
!**/src/main/**/build/
!**/src/test/**/build/

### VS Code ###
.vscode/

### Git ###
.git/

### Docker related ###
Dockerfile
.dockerignore

Building Image and Running Container

We’ll kick things off by initiating the Docker image creation using the above-mentioned Dockerfile by running docker build --build-arg VERSION=0.0.1 -t spring-boot-demo-app .

We can verify, if the image has been created or not, by running docker images command.

Docker images command will list all images

Once we have the image, we can run the container, by running docker run -p 8080:8080 --name spring-boot-demo-app-container spring-boot-demo-app

That’s it, your application should be running on the port 8080.

Now let’s dive into the best practices we’ve incorporated in the above-mentioned code.

Best Practices

Choose official and verified image

When Dockerizing our Spring Boot application, we begin with official and verified base images relevant to Java and Spring Boot. For example, we have chosen maven and openjdk for our use case.

Choose specific image version

To enhance predictability, we opt for explicit image tagging instead of relying on latest tag, ensuring stability.

Choose lightweight images

We opt for smaller base images like alpine or slim to enhance portability and reduce vulnerability.

Optimizing image layer caching

Structuring the Dockerfile for optimized caching involves arranging commands from the least to most frequently changing. For instance, we start by copying only the pom.xml file, followed by installing dependencies, copying the source code, and, lastly, packaging it.

Leveraging .dockerignore file

Folks who have used Git must be familiar with this concept. Reduce image size and improve build performance by trimming unnecessary files with a .dockerignore file.

Employing multi-stage builds

Optimize efficiency and minimize the final image size using multi-stage builds, ensuring a streamlined Dockerized application. In the first stage, we compile the Spring Boot application using Maven, and subsequently, in the second stage, we deploy it using the JRE, utilizing the WAR file generated in the initial stage.

User privilege management

Adhere to the principle of least privilege by avoiding running containers with root user privileges, enhancing security. As an example, we’ve established a user named springuser and transitioned to its utilization.

Memory constraints

Set memory constraints for your Spring Boot application within the Docker CMD, specifying an Xmx value, for example, Xmx256m for 256 MB.

To sum up, by walking through these examples, you’ve gained insights into Docker best practices tailored for Spring Boot applications. Dockerization doesn’t have to be complex; it’s about making smart choices. So, with these practices, go ahead and Dockerize your applications.

--

--

Full stack Dev and Lead @ Texas Instruments. Follow me for short articles on software development.