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:
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)
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
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).
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。