DEV Community

Alif Ruliarso
Alif Ruliarso

Posted on

Crafting Lean Java Runtimes with jlink: SpringBoot Docker

In my last adventure into the realm of Spring Boot and Docker, we explored the art of creating compact images using a JRE base. The journey was enlightening, but the quest for minimalism in Docker images never truly ends. So, let's embark on a new escapade, this time armed with the mighty jlink command.

Why jlink?

We love our Java applications, but we're not fans of oversized Docker images. jlink steps in to shrink the footprint by creating a runtime that contains only the modules required for our app. Smaller images mean faster downloads, quicker startups, and happier users.

Before we can use jlink, we need to determine which JDK modules are required by the application. We need Jdeps, a Java dependency analysis tool to list all the module dependencies.
To know more about how to use jdeps with the Spring Boot project you can look at this article.

Run JLink to create a custom Java Runtime

We added the jlink execution at the build stage. Later in the final stage, will copy the output into the final image.

RUN jlink -v \
    --add-modules java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
    --strip-debug \
    --compress 2 \
    --no-header-files \
    --no-man-pages \
    --vendor-version="i made this" \
    --output /customjre
Enter fullscreen mode Exit fullscreen mode

Arguments:

  • add-modules Adds the modules, to the default set of root modules. The module's name was generated by jdeps.
  • strip-debug will remove debugging information from the output runtime image.
  • compress=0|1|2 Enable compression of resources: 0= no compression, 1= string deduplication, 2= zip-compressed. This might influence startup time slightly.
  • vendor-version="I made this" will appear on the second line of the output of java -version
  • no-header-files Excludes header files.
  • no-man-pages Excludes man pages.
  • output Specifies the location of the generated runtime image.

After creating the custom JRE, we copy it into the JAVA_HOME of the final stage. The full dockerfile can be found here.

FROM alpine:3.18.4
ENV JAVA_HOME /user/java/jdk21
ENV PATH ${JAVA_HOME}/bin:$PATH
COPY --from=java-build /customjre ${JAVA_HOME}
Enter fullscreen mode Exit fullscreen mode

After rebuilding the docker image, here is the final result:

Image description

We reduced the image size from 232MB to 98 MB. Finally, we have a smaller docker image of the Spring Boot application using Alpine Linux and Open JDK21.

Top comments (0)