How to minimize Docker image size for Spring Boot Applications

How to minimize Docker image size for Spring Boot Applications
Photo by Daniel K Cheung / Unsplash

Introduction

Image size matters in the cloud-native application world. No one wants to see a large image size in the image repository. In short, to remember why image size is important;

  1. Efficient Distribution: Smaller image sizes allow for faster and more efficient distribution of containers across networks.
  2. Faster Deployment: Smaller images result in faster container startup times.
  3. Optimized Resource Utilization: Docker images are stored and run on Docker hosts. Smaller image sizes require less disk space, optimising resource utilization on the host machine.
  4. Security: Smaller images reduce the attack surface and potential vulnerabilities.
  5. Version Control and Maintenance: Smaller images are easier to manage, update, and version control. When you have smaller images, updating or modifying specific components becomes less complex and time-consuming.

Let's find out how we can reduce the Spring Boot image size.

Java jlink is a command-line tool introduced in Java 9 as a part of the Java 9 modules.  It allows you to create a custom runtime image that includes only the necessary modules and dependencies required by your Java application, thereby reducing its size and improving startup time.

Here's why you might need jlink:

  1. Reduced application size
  2. Faster startup time
  3. Modularization support
  4. Deployment flexibility

To use jlink, you need to define a module descriptor (module-info.java) for your application, which specifies the modules your application requires and exposes to other modules. Then, you can use the jlink command-line tool to create a custom runtime image based on those module dependencies.

Overall, jlink empowers developers to create optimized, standalone Java applications tailored to their specific requirements, leading to improved performance and a more efficient deployment process.

Docker file with Builder Image

Using a Docker builder image provides several benefits when it comes to building and packaging applications within a Docker environment. Here are some reasons:

  1. Isolation and reproducibility
  2. Consistent development and production environments
  3. Dependency management
  4. Scalability and portability
  5. Build optimizations
  6. Continuous integration and deployment (CI/CD)

Overall, Docker builder images simplify the process of building applications by providing an isolated, reproducible, and consistent environment. They help streamline the development workflow, enhance collaboration, and improve the overall efficiency of building and packaging applications within a Docker ecosystem.

Sample Dockerfile

# Custom Java runtime using jlink in a multi-stage container build
FROM eclipse-temurin:17 as jre-build

# Create a custom Java runtime
RUN $JAVA_HOME/bin/jlink \
         --add-modules jdk.unsupported,java.base,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
         --strip-debug \
         --no-man-pages \
         --no-header-files \
         --compress=2 \
         --output /javaruntime

# Define your base image
FROM debian:stretch-slim
ENV JAVA_HOME=/opt/java/openjdk
ENV PATH "${JAVA_HOME}/bin:${PATH}"
COPY --from=jre-build /javaruntime $JAVA_HOME

RUN mkdir /opt/app
COPY target/*.jar /opt/app/app.jar
CMD ["java", "-jar", "/opt/app/app.jar"]

If you have a Spring Boot application with a size of about 50 MB, the sample Dockerfile will create a 150 MB image for you.

Conclusion

In this article, I have covered Jlink and Docker builder image configuration for the smallest Spring Boot docker images. I hope it will be helpful.

See you in the next article.  👻