Document new Docker-related features
Closes gh-19868
This commit is contained in:
@@ -7703,6 +7703,154 @@ If you need the `Mockk` equivalent of the Mockito specific <<boot-features-testi
|
||||
|
||||
|
||||
|
||||
[[building-docker-images]]
|
||||
=== Building Docker Images
|
||||
Spring Boot applications can be containerized by packaging them into Docker images.
|
||||
A typical Spring Boot fat jar can be converted into a Docker image by adding just a few lines to a Dockerfile that can be used to build the image.
|
||||
However, there are various downsides to copying and running the fat jar as is in the docker image.
|
||||
There’s always a certain amount of overhead when running a fat jar without unpacking it, and in a containerized environment this can be noticeable.
|
||||
The other issue is that putting your application's code and all it's dependencies in one layer in the Docker image is sub-optimal.
|
||||
Since you probably recompile your code more often than you upgrade the version of Spring Boot you use, it’s often better to separate things a bit more.
|
||||
If you put jar files in the layer before your application classes, Docker often only needs to change the very bottom layer and can pick others up from its cache.
|
||||
|
||||
==== Layered Jars
|
||||
To make it easier to create optimized Docker images that can be built with a dockerfile, Spring Boot supports "layered jars".
|
||||
A regular fat jar that can be run with `java -jar` has the following structure:
|
||||
|
||||
[source]
|
||||
----
|
||||
META-INF/
|
||||
MANIFEST.MF
|
||||
org/
|
||||
springframework/
|
||||
boot/
|
||||
loader/
|
||||
...
|
||||
BOOT-INF/
|
||||
classes/
|
||||
...
|
||||
lib/
|
||||
...
|
||||
----
|
||||
|
||||
The jar is organized into three main parts:
|
||||
|
||||
* Classes used to bootstrap jar loading
|
||||
* Your application classes in `BOOT-INF/classes`
|
||||
* Dependencies in `BOOT-INF/lib`
|
||||
|
||||
Instead of the above jar, you can create a layered jar that looks something like this:
|
||||
|
||||
[source]
|
||||
----
|
||||
META-INF/
|
||||
MANIFEST.MF
|
||||
org/
|
||||
springframework/
|
||||
boot/
|
||||
loader/
|
||||
...
|
||||
BOOT-INF/
|
||||
layers/
|
||||
<name>/
|
||||
classes/
|
||||
...
|
||||
lib/
|
||||
...
|
||||
<name>/
|
||||
classes/
|
||||
...
|
||||
lib/
|
||||
...
|
||||
layers.idx
|
||||
----
|
||||
|
||||
You still see the bootstrap loader classes (you can still run `java -jar`) but now the `lib` and `classes` folders have been split up and categorized into layers.
|
||||
There’s also a `layers.idx` file that provides the order in which layers should be added.
|
||||
Out-of-the-box, the following layers are supported:
|
||||
|
||||
* `dependencies` (for regular released dependencies)
|
||||
* `snapshot-dependencies` (for snapshot dependencies)
|
||||
* `resources` (for static resources)
|
||||
* `application` (for application classes and resources)
|
||||
|
||||
|
||||
This layering is designed to separate code based on how likely it is to change between application builds.
|
||||
Library code is less likely to change between builds, so it is placed in its own layers to allow tooling to re-use the layers from cache.
|
||||
Application code is more likely to change between builds so it is isolated in a separate layer.
|
||||
|
||||
For Maven, layered jars can be created using a new `layout` type called `LAYERED_JAR`.
|
||||
See the {spring-boot-maven-plugin-docs}/#goals-build-image-parameters-details-layout[layout section] for more details.
|
||||
For Gradle, refer to the {spring-boot-gradle-plugin-docs}/#packaging-layered-jars[packaging layered jars section] of the Gradle plugin documentation.
|
||||
|
||||
==== Writing the Dockerfile
|
||||
|
||||
When you create a layered jar, the `spring-boot-layertools` 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.
|
||||
Here’s how you can launch your jar with a `layertools` jar mode:
|
||||
|
||||
[source]
|
||||
----
|
||||
$ java -Djarmode=layertools -jar my-app.jar
|
||||
----
|
||||
|
||||
This will provide the following output:
|
||||
|
||||
[source]
|
||||
----
|
||||
Usage:
|
||||
java -Djarmode=layertools -jar my-app.jar
|
||||
|
||||
Available commands:
|
||||
list List layers from the jar that can be extracted
|
||||
extract Extracts layers from the jar for image creation
|
||||
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's an example of a Dockerfile using `jarmode`.
|
||||
|
||||
[source]
|
||||
----
|
||||
FROM adoptopenjdk:11-jre-hotspot as builder
|
||||
WORKDIR application
|
||||
ARG JAR_FILE=target/*.jar
|
||||
COPY ${JAR_FILE} application.jar
|
||||
RUN java -Djarmode=layertools -jar application.jar extract
|
||||
|
||||
FROM adoptopenjdk:11-jre-hotspot
|
||||
WORKDIR application
|
||||
COPY --from=builder application/dependencies/ ./
|
||||
COPY --from=builder application/snapshot-dependencies/ ./
|
||||
COPY --from=builder application/resources/ ./
|
||||
COPY --from=builder application/application/ ./
|
||||
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
|
||||
----
|
||||
|
||||
This is a multi-stage dockerfile.
|
||||
The builder stage extracts the folders 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.
|
||||
|
||||
|
||||
|
||||
==== Buildpacks
|
||||
Dockerfiles are just one way to build docker images.
|
||||
Another way to build docker images is directly from your Maven or Gradle plugin, using buildpacks.
|
||||
If you’ve ever used an application platform such as Cloud Foundry or Heroku then you’ve probably used a buildpack.
|
||||
Buildpacks are the part of the platform that takes your application and converts it into something that the platform can actually run.
|
||||
For example, Cloud Foundry’s Java buildpack will notice that you’re pushing a `.jar` file and automatically add a relevant JRE.
|
||||
|
||||
With Cloud Native Buildpacks, you can create Docker compatible images that you can run anywhere.
|
||||
Spring Boot includes buildpack support directly for both Maven and Gradle.
|
||||
This means you can just type a single command and quickly get a sensible image into your locally running Docker daemon.
|
||||
|
||||
Refer to the individual plugin documentation on how to use buildpacks with {spring-boot-maven-plugin-docs}/#build-image[Maven] and {spring-boot-gradle-plugin-docs}/#packaging-oci-images[Gradle].
|
||||
|
||||
|
||||
|
||||
[[boot-features-whats-next]]
|
||||
== What to Read Next
|
||||
If you want to learn more about any of the classes discussed in this section, you can check out the {spring-boot-api}[Spring Boot API documentation] or you can browse the {spring-boot-code}[source code directly].
|
||||
|
||||
Reference in New Issue
Block a user