Create Smaller Docker Images For Spring Boot Using JLink
Containers revolutionise software development and deployment by providing unparalleled flexibility and agility, fundamentally reshaping the landscape of application development and scalability. However, this transformative technology brings with it a new vulnerability landscape that malicious actors can exploit. A compromised container not only jeopardizes its integrity but also opens pathways for attackers to infiltrate other containers and potentially compromise the host system.
Mitigating this risk requires adopting practices such as utilizing smaller images containing only essential artifacts, which effectively reduces the attack surface. Additionally, employing compact application containers minimises resource consumption, enhancing security while optimising runtime performance, by providing shorter startup duration and smaller size for jar files.
In this article we will study in-depth utilisation of JLink to optimise docker image size of any spring boot or java application, to enhance application security and usage of only required modules and dependencies.
Project Jigsaw
Project jigsaw was introduced in JDK 9 with primary goals of
Introduction of JLink
Java is one of the most used programming language specially for enterprise applications, but one biggest challenge developer faced are size of docker images while deploying java application in container. One of the way to solve this problem is to use JLink.
JLink was introduced as the part of project Jigsaw. JLink (Java linker) is a command line tool that assemble and optimise a set of modules and their dependencies into a custom runtime image. It means that JLink create a minimum java runtime with only required modules and their dependencies for project.
$ jlink --module-path $JAVA_HOME/jmods:testLib --add-modules test.module --output testRunTime
In above example, test.module are module we want to add and testRunTime is runtime image which jLink will create.
Small Docker Images Using JLink
When we write docker images for java applications, size of image is concerning, specially spring boot applications which come with plenty of dependencies and modules. A large docker image can lead latency during start up, increased storage costs and slower development process.
In older version of java (priori to JDK 11) java development kit comes with a java runtime environment (JRE). Only JRE was needed to run java artefacts (jars). When we used to create docker file then we only need JRE base image to run our java jars in our containers. Onwards JDK 11, JRE is no longer offered but only JDK (embedded with all runtime required to run java artefacts including some additional tools like compiler, executables and binaries). Now when we create docker images we required to use JDK which cause larger runtimes.
JLink enable us to create a minimal java runtime with only necessary modules and its dependencies. By doing this, it significantly reduces the size of our docker image, for example a standard java runtime environment might be 150 MB - 200 MB while using JLink reduce it to 20 MB to 50 MB.
JLink for Spring Boot
Spring boot create a fat jar for our applications containing all dependencies required by spring boot. We wanted to use only those dependencies and modules which are needed by our application. Imagine our application is a very simple CRUD application so our application only needed modules required for creating end points and CRUD functionalities.
We need to determine which modules the application need along with its dependencies.
Jdeps Usage
Jdeps a Java 8 tool that helps us to determine all package and class level dependencies and modules of an application. First we will figure out all dependencies and modules using Jdeps and will pass those to our JLink to create concise and smaller runtime for our application by using only required dependencies.
we can use jdeps to print a summary of the dependencies.
jdeps -cp 'mydeps/lib/*' -recursive --multi-release 17 -s target/Websocket.jar
Similarly, we can use jdeps to print all module dependencies recursively for the Spring Boot application and the dependencies.
jdeps --ignore-missing-deps -q --recursive --multi-release 17 --print-module-deps --class-path 'mydeps/lib/*' target/Websocket.jar
The output generated by jdeps enables JLink to create a Java Runtime that only contains the modules needed for this Spring-Boot application.
We store information of dependencies and modules in a file before passing this to JLink.
RUN jdeps --ignore-missing-deps -q \ --recursive \ --multi-release 17 \ --print-module-deps \ --class-path 'BOOT-INF/lib/*' \ target/Websocket.jar > deps.info
Building Docker Image
Let’s combine Jdeps and JLink to build a custom Java Runtime. With this runtime, we can create a perfect, minimal Docker image specifically for a Spring Boot application.
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/Websocket.jar
RUN jdeps --ignore-missing-deps -q \
--recursive \
--multi-release 17 \
--print-module-deps \
--class-path 'BOOT-INF/lib/*' \
target/Websocket.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
RUN mkdir /project
COPY --from=build /usr/src/project/target/Websocket.jar /project/
WORKDIR /project
ENTRYPOINT java -jar Websocket.jar
In above example, we created a multistage docker build. The initial building stage based on an eclipse-temurin JDK 17 image containing Maven. This stage is used to:
Conclusion
As in this article we study how we can utilise JLink from project jigsaw to create small, light weight docker image by provide custom runtime environment having only those modules and dependencies required by application. To determine our application dependencies and modules we use Jdeps from JDK 8. Smaller docker images lead faster development and reduced storage cost. Beside that it also provide faster startup and reduce the attack surface of application by providing only necessary modules.
Artificial Intelligence | Python |Machine Learning | Deep Learning | Exlporatory Data Analysis
7 个月Excellent ??