Skip to content

Commit

Permalink
Improve docker without buildpacks documentation
Browse files Browse the repository at this point in the history
Explain how CDS can be enabled with plain Dockerfiles.

Closes gh-42106
  • Loading branch information
mhalbritter committed Sep 4, 2024
1 parent 599f1f1 commit 8d44fd5
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ This will cause the buildpack to do a training run of the application, save the

The Paketo Buildpack for Spring Boot https://github.com/paketo-buildpacks/spring-boot?tab=readme-ov-file#configuration[documentation] has information on other configuration options that can be enabled with builder environment variables, like `CDS_TRAINING_JAVA_TOOL_OPTIONS` that allows to override the default `JAVA_TOOL_OPTIONS`, only for the CDS training run.

[[howto.class-data-sharing.dockerfiles]]
== Packaging an Application Using CDS and Dockerfiles

If you don't want to use Cloud Native Buildpacks, it is also possible to use CDS with a `Dockerfile`.
For more information about that, please see the xref:reference:packaging/container-images/dockerfiles.adoc#packaging.container-images.dockerfiles.cds[Dockerfiles reference documentation].

[[howto.class-data-sharing.training-run-configuration]]
== Preventing Remote Services Interaction During the Training Run

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[[packaging.container-images.dockerfiles]]
= 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 xref:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[layering feature] will result in an optimized image.
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 xref:packaging/container-images/efficient-images.adoc#packaging.container-images.efficient-images.layering[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.

Expand All @@ -28,32 +28,12 @@ Available commands:
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`.
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`.

[source,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/ ./
include::reference:partial$dockerfile[]
# 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
Expand All @@ -67,10 +47,31 @@ Assuming the above `Dockerfile` is in the current directory, your Docker image c
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
----

This is a multi-stage Dockerfile.
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`.
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.



[[packaging.container-images.dockerfiles.cds]]
== CDS

If you want to additionally enable xref:reference:packaging/class-data-sharing.adoc[CDS], you can use this `Dockerfile`:
[source,dockerfile]
----
include::reference:partial$dockerfile[]
# 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`.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# 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/ ./

0 comments on commit 8d44fd5

Please sign in to comment.