Original Spring Boot 2.3 new features layered JAR

Posted May 25, 20205 min read

background

In our actual production containerized deployment process, we often encounter the situation that the Docker image is very large and the deployment and release are very slow

The factors that affect the size of the docker image mainly include the following three aspects:

    1. The size of the base image. Try to choose aphine as the base image to reduce the built-in software of the operating system
    1. Dockerfile instruction layer. This requires us to optimize the Dockerfile to be merged in one line, try to merge, etc.
    1. The size of the application jar. This is the key content to share today

helloworld mirror

Let's first build a simple web helloworld based on spring boot 2.3.0, and then build an image.

FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE = target/*. Jar
COPY ${JAR_FILE} application.jar
ENTRYPOINT ["java", "-jar application.jar"]

docker build --build-arg JAR_FILE =./demo-layer-0.0.1-SNAPSHOT.jar. -t demo:v1.0

View image layering information

Let's take a look at the hash value of each layer of this image through docker inspect demo:v1.0

//demo:summary of the layered information of the v1.0 version image
"Layers":[
    "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
    "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
    "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
    "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
    "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
    "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
    "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
    "sha256:b87d2ff74819f83038ea2f89736a19cfcf99bfa080b8017d191c900a09a7524f"

]

helloworld upgrade and rebuild

We make some modifications to the helloworld program(simulate the development process), and then rebuild the image

docker build --build-arg JAR_FILE =./demo-layer-0.0.1-SNAPSHOT.jar. -t demo:v1.1

At this time, the image layering information is as follows docker inspect demo:v1.1

//demo:summary of layered information of v1.1 version image
"Layers":[
    "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
    "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
    "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
    "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
    "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
    "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
    "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
    "sha256:c1b6350d545fea605e0605c4bfd7f4529cfeee3f6759750d6a5ddeb9c882fc8f"

]

Compare v1.0 and v1.1 images

By comparing the image summary information of v1.0 and v1.1 versions, we will find that only the last layer has changed. We passed [Dive is a Docker image analysis tool written in Go language]( https://github . com/wagoodman/dive) to determine what the last layer did

dive demo:v1.0, You will see that the last jar is different, resulting in 16M content needs to be rebuilt. When your business jar is very large, this is the performance bottleneck

spring boot default package decryption

By default, the jar built by spring boot can see the following directory structure after decompression. By default, it will be regarded as a whole, as a separate layer when building the image, There is no distinction between business classes and referenced third-party jars

META-INF /
  MANIFEST.MF
org /
  springframework /
    boot /
      loader /
BOOT-INF /
  classes /
  lib /

layer jar

From the above, you can know that the idea of layered jar is to subdivide jar according to rules, business class and three-party jar correspond to different layers of the mirror, so to change the business code, only a small amount of content needs to be changed to improve the construction speed.

Enable layered packaging

  <plugin>
    <groupId> org.springframework.boot </groupId>
    <artifactId> spring-boot-maven-plugin </artifactId>
    <configuration>
      <layers>
        <enabled> true </enabled>
      </layers>
    </configuration>
  </plugin>

Writing support for layered Dockerfile

The core is to use the layertools tool provided by spring boot, split the jar and then load it separately through the COPY instruction

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/spring-boot-loader/./
COPY --from = builder application/snapshot-dependencies/./
COPY --from = builder application/application/./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

Build a new image and view layered information

docker build --build-arg JAR_FILE =./demo-layer-0.0.1-SNAPSHOT.jar. -t demo:v2.0

"Layers":[
    "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
    "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
    "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
    "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
    "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
    "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
    "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
    "sha256:06fe18cf8ae7384f120f2c6a3a33b31999dd0460cf1edae45e8f13adeab35942",
    "sha256:16cf814564b8a667fcc9f07314b6084cbef8dc8c0a6565c7a2d91d74faf7e7de",
    "sha256:94be40f716016b68cdd6b99d2cb8154acf8475c3a170a898a22f95a8ef40ffd3",
    "sha256:427d87d6a5fe6da13cb4233939c3a1ff920bc6b4d2f14b5d78af7aef98fda7de"

]

Modify some business codes of the code and rebuild

docker build --build-arg JAR_FILE =./demo-layer-0.0.1-SNAPSHOT.jar. -t demo:v2.1

"Layers":[
    "sha256:b7f7d2967507ba709dbd1dd0426a5b0cdbe1ff936c131f8958c8d0f910eea19e",
    "sha256:a6ebef4a95c345c844c2bf43ffda8e36dd6e053887dd6e283ad616dcc2376be6",
    "sha256:838a37a24627f72df512926fc846dd97c93781cf145690516e23335cc0c27794",
    "sha256:28ba7458d04b8551ff45d2e17dc2abb768bf6ed1a46bb262f26a24d21d8d7233",
    "sha256:55c91231ac46fdd63c3cf84b88b11f8a04c1870482dcff033029a601bc50e1ab",
    "sha256:9816c2d488754509f6024a267738b1e5fe33a7cd33bd25c5a9cdf6d4d7bfed1d",
    "sha256:f5fb3f91797d57a92f3f7e033398b8edd094df664db849a4950eabf2f5474535",
    "sha256:06fe18cf8ae7384f120f2c6a3a33b31999dd0460cf1edae45e8f13adeab35942",
    "sha256:16cf814564b8a667fcc9f07314b6084cbef8dc8c0a6565c7a2d91d74faf7e7de",
    "sha256:94be40f716016b68cdd6b99d2cb8154acf8475c3a170a898a22f95a8ef40ffd3",
    "sha256:8a20c60d361696a4e480fb6fbe1daf8b88bc54c579a98e209da1fb76e25de5aa"

]

View the difference layer mirror

The last layer change size is 5KB

to sum up

image