From 0e1394ef3042eacfd1d340a2c846b66bd0331ab8 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 2 Apr 2020 23:27:47 -0700 Subject: [PATCH] Update reference documentation for layer changes Update the reference documentation following the jar format changes. See gh-20813 --- .../src/docs/asciidoc/deployment.adoc | 29 +------ .../docs/asciidoc/spring-boot-features.adoc | 85 ++++++------------- 2 files changed, 31 insertions(+), 83 deletions(-) diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment.adoc index ddb207c3da8..b67b05535d9 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/deployment.adoc @@ -33,33 +33,10 @@ Once you have unpacked the jar file, you can also get an extra boost to startup $ java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication ---- -More efficient container images can also be created by copying the dependencies to the image as a separate layer from the application classes and resources (which normally change more frequently). -There is more than one way to achieve this layer separation. -For example, using a `Dockerfile` you could express it in this form: +NOTE: Using the `JarLauncher` over the application's main method has the added benefit of a predictable classpath order. +The jar contains a `classpath.idx` file which is used by the `JarLauncher` when constructing the classpath. -[indent=0] ----- - FROM openjdk:8-jdk-alpine AS builder - WORKDIR target/dependency - ARG APPJAR=target/*.jar - COPY ${APPJAR} app.jar - RUN jar -xf ./app.jar - - FROM openjdk:8-jre-alpine - VOLUME /tmp - ARG DEPENDENCY=target/dependency - COPY --from=builder ${DEPENDENCY}/BOOT-INF/lib /app/lib - COPY --from=builder ${DEPENDENCY}/META-INF /app/META-INF - COPY --from=builder ${DEPENDENCY}/BOOT-INF/classes /app - ENTRYPOINT ["java","-cp","app:app/lib/*","com.example.MyApplication"] ----- - -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: - -[indent=0] ----- - docker build --build-arg APPJAR=path/to/myapp.jar . ----- +More efficient container images can also be created by <> for your dependencies and application classes and resources (which normally change more frequently). diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 017379339ee..f47e78b09a3 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -7996,77 +7996,41 @@ The other issue is that putting your application's code and all its dependencies 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/ - / - classes/ - ... - lib/ - ... - / - 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. +=== Layering Docker Images +To make it easier to create optimized Docker images that can be built with a dockerfile, Spring Boot supports adding a layer index file to the jar. +The `layers.idx` file lists all the files in the jar along with the layer that the file should go in. +The list of files in the index is ordered based on the order in which the layers should be added. Out-of-the-box, the following layers are supported: * `dependencies` (for regular released dependencies) +* `spring-boot-loader` (for everything under `org/springframework/boot/loader`) * `snapshot-dependencies` (for snapshot dependencies) -* `resources` (for static resources) * `application` (for application classes and resources) +The following shows an example of a `layers.idx` file: + +[source] +---- +dependencies BOOT-INF/lib/library1.jar +dependencies BOOT-INF/lib/library2.jar +spring-boot-loader org/springframework/boot/loader/JarLauncher.class +spring-boot-loader org/springframework/boot/loader/jar/JarEntry.class +... +snapshot-dependencies BOOT-INF/lib/library3-SNAPSHOT.jar +application META-INF/MANIFEST.MF +application BOOT-INF/classes/a/b/C.class +---- 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, refer to the {spring-boot-maven-plugin-docs}/#repackage-layered-jars[packaging layered jars section] for more details on creating a layered jar. +For Maven, refer to the {spring-boot-maven-plugin-docs}/#repackage-layered-jars[packaging layered jars section] for more details on adding a layer index to the jar. 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 + +=== Writing the Dockerfile When you create a layered jar, the `spring-boot-jarmode-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: @@ -8109,6 +8073,13 @@ COPY --from=builder application/application/ ./ ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"] ---- +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: + +[indent=0] +---- + docker build --build-arg JAR_FILE=path/to/myapp.jar . +---- + 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.