Dockerizing Spring Boot Application: Adhering to 8 Best Practices
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.
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.
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.