1
头图

I. Overview

Starting with spring boot 2.3, the spring-boot-maven-plugin plug-in enables hierarchical construction of the jar package or war package by default. This article mainly records how to use the hierarchical jar to build an image based on official documents.

Two, spring-boot-maven-plugin layered construction jar package

Configure the spring boot project inherited from spring-boot-starter-parent , set <parent> as follows:

<!-- Inherit defaults from Spring Boot -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.5.1</version>
</parent>

The project inherited from spring-boot-starter-parent has the following default configuration:

  • Compile jdk by default: JDK 1.8
  • Default encoding: UTF-8
  • The default dependency management part is inherited from spring-boot-dependencies POM , which manages the version of common dependencies. This dependency management allows you to omit the <version> tags of those dependencies when you use them in your own POM
  • The excution goal of the default configuration is: repackage

spring-boot-maven-plugin plug-in is introduced into the project, the layered construction of the jar package is turned on by default. We can use the following methods to verify:

  • Add the following plug-in configuration to the pom.xml file of the project:

    <project>
      <modelVersion>4.0.0</modelVersion>
      <artifactId>getting-started</artifactId>
      <!-- ... -->
      <build>
          <plugins>
              <plugin>
                  <groupId>org.springframework.boot</groupId>
                  <artifactId>spring-boot-maven-plugin</artifactId>
              </plugin>
          </plugins>
      </build>
    </project>
    
  • Execute the following command to package:

    mvn clean package 

    Generate the corresponding jar package under the target directory, and unzip the jar package directory structure as follows:

image.png

The jar contains application classes and dependencies BOOT-INF/classes and BOOT-INF/lib Similarly, comprising executable war WEB-INF/classes the application classes and WEB-INF/lib and WEB-INF/lib-provided in dependency. For situations where you need to build a docker image from the contents of a jar or war, you need to separate these directories so that they can be written to different layers.

The BOOT-INF/layers.idx file is used to define the build order of the hierarchical jar. The order of the layers is very important because it determines that when a part of the application changes, the changed content should be put behind as much as possible, and the most recent should be added first. It is impossible to change the content, and then add the most likely to change the layer, the default order is:

  • dependencies (used to store dependencies that do not contain snapshots)
  • spring-boot-loader (used to store class loader)
  • snapshot-dependencies (used to store dependencies containing snapshots)
  • application (used to store classes and resources of the application)

image.png

This layering aims to separate the code based on the possibility of changes between application builds. The dependencies of the project are unlikely to change frequently between internal versions, so it is placed in a separate layer dependencies to allow tools to reuse the cache The application code is more likely to change between internal versions, so it is isolated in a separate layer application .

Use the following command to view the directory order of the hierarchical jar:

java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar list

dependencies
spring-boot-loader
snapshot-dependencies
application

Use the following command to decompress the jar package according to the hierarchical directory structure to create a hierarchical image:

java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.jar extract

The java -Djarmode=layertools -jar application.jar are as follows:

Usage:
  java -Djarmode=layertools -jar probedemo-0.0.1-SNAPSHOT.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

To disable this feature, you can use the following methods


<project>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <layers>
                        <enabled>false</enabled>
                    </layers>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Three, multi-stage construction of docker image

After knowing the build directory of the above hierarchical jar package, we can use multiple stages to build the docker image. Dockerfile is as follows:

# 指定基础镜像,这是多阶段构建的前期阶段
FROM openjdk:11-jre-slim as builder
# 指定工作目录,目录不存在会自动创建
WORKDIR /app
# 将生成的 jar 复制到容器镜像中
COPY target/*.jar application.jar
# 通过工具spring-boot-jarmode-layertools从application.jar中提取拆分后的构建结果
RUN java -Djarmode=layertools -jar application.jar extract

# 正式构建镜像
FROM openjdk:11-jre-slim
# 指定工作目录,目录不存在会自动创建
WORKDIR /app
# 前一阶段从jar中提取除了多个文件,这里分别执行COPY命令复制到镜像空间中,每次COPY都是一个layer
COPY --from=builder app/dependencies ./
COPY --from=builder app/spring-boot-loader ./
COPY --from=builder app/snapshot-dependencies ./
COPY --from=builder app/application ./
# 指定时区
ENV TZ="Asia/Shanghai"
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 定义一些环境变量,方便环境变量传参
ENV JVM_OPTS=""
ENV JAVA_OPTS=""
# 指定暴露的端口,起到说明的作用,不指定也会暴露对应端口
EXPOSE 8080
# 启动 jar 的命令
ENTRYPOINT ["sh","-c","java $JVM_OPTS $JAVA_OPTS org.springframework.boot.loader.JarLauncher"]

Use the following command to build the docker image:

docker build -t demo:1.0.0 . 

Use the following command to view the hierarchical information of the image:

docker history demo:1.0.0

image.png

As shown in the figure above, the contents of the entire jar, such as classes, dependent libraries, dependent resources, etc., are copied to the mirror space multiple times, so if you only change the class in the future, when you update the mirror, you only need to download the layer of the class ( Other layers can directly use the previously cached locally).

image.png

Reference article:

https://docs.spring.io/spring-boot/docs/2.5.1/maven-plugin/reference/htmlsingle/#packaging.layers

https://blog.csdn.net/boling_cavalry/article/details/106598189


惜鸟
328 声望2.3k 粉丝