How to Shrink Spring Boot Docker Images with JLink
This guide explains how to use JLink together with jdeps and a multi‑stage Docker build to create a minimal custom Java runtime, reducing Spring Boot Docker image size from over 200 MB to under 50 MB while improving startup speed and security.
In this article we explore how to leverage JLink to reduce Docker image size for Spring Boot or generic Java applications, thereby improving security and performance.
When packaging Java applications in Docker, image size often becomes a problem, especially for Spring Boot apps that bundle many dependencies. Large images increase startup time, storage cost, and deployment latency.
JLink (Java Linker) is a command‑line tool introduced in JDK 9 that assembles a set of modules and their dependencies into a custom runtime image. By including only the modules required by the application, the resulting Java runtime can be dramatically smaller—for example, a standard JRE may exceed 200 MB, while a JLink‑generated runtime can be under 50 MB.
Because Spring Boot produces a fat JAR that typically lacks explicit module declarations, we first need to determine which modules are required. This is done with jdeps, a tool that reports package‑level or class‑level dependencies.
jlink --module-path $JAVA_HOME/jmods:mlib --add-modules my.module --output myRunTimeExample jdeps commands used to list the modules for a Spring Boot JAR:
jdeps -cp 'mydeps/lib/*' -recursive --multi-release 17 -s target/MyJar.jar jdeps --ignore-missing-deps -q --recursive --multi-release 17 --print-module-deps --class-path 'mydeps/lib/*' target/MyJar.jarThe output of jdeps provides the module list that JLink will consume.
Spring Boot’s fat JAR packages dependencies inside the JAR, making them inaccessible to jdeps. Two practical ways to expose the dependencies are:
Unzip the fat JAR and locate the dependencies under /BOOT/libs/.
Use the Maven Dependency Plugin to copy dependencies to a dedicated folder during the build.
<project>
…
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.2</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/dependency</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
…
</project>With the module list ready, we combine jdeps and JLink in a multi‑stage Docker build to produce a minimal runtime image:
FROM maven:3-eclipse-temurin-17 as build
RUN mkdir /usr/src/project
COPY . /usr/src/project
WORKDIR /usr/src/project
RUN mvn package -DskipTests
RUN jar xf target/JavaCoffeeShop.jar
RUN jdeps --ignore-missing-deps -q \
--recursive \
--multi-release 17 \
--print-module-deps \
--class-path 'BOOT-INF/lib/*' \
target/JavaCoffeeShop.jar > deps.info
RUN jlink \
--add-modules $(cat deps.info) \
--strip-debug \
--compress 2 \
--no-header-files \
--no-man-pages \
--output /myjre
FROM debian:bookworm-slim
ENV JAVA_HOME /user/java/jdk17
ENV PATH $JAVA_HOME/bin:$PATH
COPY --from=build /myjre $JAVA_HOME
COPY --from=build /usr/src/project/target/JavaCoffeeShop.jar /project/
WORKDIR /project
ENTRYPOINT java -jar JavaCoffeeShop.jarThe first stage builds the application with Maven, extracts the fat JAR, runs jdeps to generate deps.info, and invokes JLink to create a stripped custom runtime stored in /myjre. The second stage starts from a slim Debian base, sets JAVA_HOME, copies the custom runtime and the application JAR, and defines the entry point.
Benefits of using JLink for Spring Boot Docker images include:
Reduced image size (often from >200 MB to < 50 MB), leading to faster deployments and lower storage costs.
Faster container startup because fewer files need to be loaded.
Improved security: a minimal runtime contains only the modules the application uses, decreasing the attack surface.
To further harden the container, the article recommends scanning the final image with Snyk, which can detect vulnerabilities in the image layers and suggest fixes: snyk container test your-repo/your-image:tag In summary, JLink is a powerful tool for creating smaller, more secure Docker images for Spring Boot Java applications, especially when combined with dependency analysis via jdeps and vulnerability scanning with Snyk.
Author: snyk<br/>Source: https://snyk.io/blog/jlink-create-docker-images-spring-boot-java/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
