Dockerfiles
While it is possible to convert a Spring Boot uber jar into a Docker image with just a few lines in the Dockerfile
, using the layering feature will result in an optimized image.
When you create a jar containing the layers index file, the spring-boot-jarmode-tools
jar will be added as a dependency to your jar.
With this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers.
The tools mode can not be used with a fully executable Spring Boot archive that includes a launch script.
Disable launch script configuration when building a jar file that is intended to be used with layertools .
|
Here’s how you can launch your jar with a tools
jar mode:
$ java -Djarmode=tools -jar my-app.jar
This will provide the following output:
Usage: java -Djarmode=tools -jar my-app.jar Available commands: extract Extract the contents from the jar list-layers List layers from the jar that can be extracted help Help about any command
The extract
command can be used to easily split the application into layers to be added to the Dockerfile
.
Here is an example of a Dockerfile
using jarmode
.
# Perform the extraction in a separate builder container
FROM bellsoft/liberica-openjre-debian:17-cds AS builder
WORKDIR /builder
# This points to the built jar file in the target folder
# Adjust this to 'build/libs/*.jar' if you're using Gradle
ARG JAR_FILE=target/*.jar
# Copy the jar file to the working directory and rename it to application.jar
COPY ${JAR_FILE} application.jar
# Extract the jar file using an efficient layout
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
# This is the runtime container
FROM bellsoft/liberica-openjre-debian:17-cds
WORKDIR /application
# Copy the extracted jar contents from the builder container into the working directory in the runtime container
# Every copy step creates a new docker layer
# This allows docker to only pull the changes it really needs
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
COPY --from=builder /builder/extracted/application/ ./
# Start the application jar - this is not the uber jar used by the builder
# This jar only contains application code and references to the extracted jar files
# This layout is efficient to start up and CDS friendly
ENTRYPOINT ["java", "-jar", "application.jar"]
Assuming the above Dockerfile
is in the current directory, your Docker image can be built with docker build .
, or optionally specifying the path to your application jar, as shown in the following example:
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
This is a multi-stage Dockerfile
.
The builder stage extracts the directories that are needed later.
Each of the COPY
commands relates to the layers extracted by the jarmode.
Of course, a Dockerfile
can be written without using the jarmode
.
You can use some combination of unzip
and mv
to move things to the right layer but jarmode
simplifies that.
Additionally, the layout created by the jarmode
is CDS friendly out of the box.
CDS
If you want to additionally enable CDS, you can use this Dockerfile
:
# Perform the extraction in a separate builder container
FROM bellsoft/liberica-openjre-debian:17-cds AS builder
WORKDIR /builder
# This points to the built jar file in the target folder
# Adjust this to 'build/libs/*.jar' if you're using Gradle
ARG JAR_FILE=target/*.jar
# Copy the jar file to the working directory and rename it to application.jar
COPY ${JAR_FILE} application.jar
# Extract the jar file using an efficient layout
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
# This is the runtime container
FROM bellsoft/liberica-openjre-debian:17-cds
WORKDIR /application
# Copy the extracted jar contents from the builder container into the working directory in the runtime container
# Every copy step creates a new docker layer
# This allows docker to only pull the changes it really needs
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
COPY --from=builder /builder/extracted/application/ ./
# Execute the CDS training run
RUN java -XX:ArchiveClassesAtExit=application.jsa -Dspring.context.exit=onRefresh -jar application.jar
# Start the application jar with CDS enabled - this is not the uber jar used by the builder
# This jar only contains application code and references to the extracted jar files
# This layout is efficient to start up and CDS friendly
ENTRYPOINT ["java", "-XX:SharedArchiveFile=application.jsa", "-jar", "application.jar"]
This is mostly the same as the above Dockerfile
.
As the last steps, it creates the CDS archive by doing a training run and passes the CDS parameter to java -jar
.