赞
踩
Spring Boot Layered Jar 是一种特殊的 Jar 包格式,由 Spring Boot 2.3 及以上版本提供。这种格式主要是为了优化 Docker 镜像的构建和部署过程。以下是关于 Spring Boot Layered Jar 的详细解释:
pom.xml
文件中为 spring-boot-maven-plugin
插件添加 <layers><enabled>true</enabled></layers>
配置。mvn package
)将生成一个包含多个层的 Jar 文件。这个文件可以使用 java -jar
命令直接运行,就像传统的 Jar 包一样。总的来说,Spring Boot Layered Jar 是一种优化 Docker 镜像构建和部署过程的解决方案。它通过分层结构减少了每次代码变更时需要重新构建和上传的数据量,从而提高了构建效率并节省了存储空间。
一个 repackaged 的jar文件在BOOT-INF/classes
和BOOT-INF/lib
中分别包含应用程序的类和依赖项。同样,一个可执行的war文件在WEB-INF/classes
中包含应用程序的类,在WEB-INF/lib和WEB-INF/lib-provided
中包含依赖项。对于那些需要从jar或war的内容构建Docker镜像的情况,能够进一步分离这些目录以便将它们写入不同的层是很有用的。
分层归档使用与普通重新打包的jar或war相同的布局,但包括一个描述每一层的附加元数据文件(layers.idx
)。
默认情况下,定义了以下层:
dependencies
:用于不包含SNAPSHOT
版本的任何依赖项。spring-boot-loader
:用于加载器类。snapshot-dependencies
:用于包含SNAPSHOT
版本的任何依赖项。application
:用于本地模块依赖项、应用程序类和资源。模块依赖项是通过查看当前构建的所有模块来识别的。如果模块依赖项只能因为已经安装到Maven的本地缓存中而得到解析,并且它不是当前构建的一部分,那么它将被识别为常规依赖项。
层的顺序很重要,因为它决定了当应用程序的某一部分发生变化时,之前的层被缓存的可能性有多大。默认顺序是dependencies
、spring-boot-loader
、snapshot-dependencies
、application
。最不可能改变的内容应该首先添加,其次是更有可能改变的层。
默认情况下,打包的jar文件中包括layers.idx
文件。要禁用此功能,您可以按以下方式进行操作:
<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>
通过将这些内容写入不同的层,可以更有效地利用Docker的缓存机制,从而提高构建效率。
根据您的应用程序需求,您可能想要调整如何创建层并添加新层。这可以通过使用一个单独的配置文件来完成,该文件的注册方式如下所示:
<project> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <layers> <enabled>true</enabled> <configuration>${project.basedir}/src/layers.xml</configuration> </layers> </configuration> </plugin> </plugins> </build> </project>
配置文件描述了如何将归档文件分离成不同的层,以及这些层的顺序。以下示例展示了如何明确定义上述默认顺序:
<layers xmlns="http://www.springframework.org/schema/boot/layers" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/boot/layers https://www.springframework.org/schema/boot/layers/layers-3.2.xsd"> <application> <into layer="spring-boot-loader"> <include>org/springframework/boot/loader/**</include> </into> <into layer="application" /> </application> <dependencies> <into layer="application"> <includeModuleDependencies /> </into> <into layer="snapshot-dependencies"> <include>*:*:*SNAPSHOT</include> </into> <into layer="dependencies" /> </dependencies> <layerOrder> <layer>dependencies</layer> <layer>spring-boot-loader</layer> <layer>snapshot-dependencies</layer> <layer>application</layer> </layerOrder> </layers>
layers XML格式在三个部分中定义:
<application>
块定义了如何将应用程序类和资源进行分层。
<dependencies>
块定义了如何将依赖项进行分层。
<layerOrder>
块定义了层应该写入的顺序。
在<application>
和<dependencies>
部分中,嵌套的<into>
块用于为层声明内容。这些块按照从上到下的定义顺序进行评估。任何未被前面的块声明的内容仍然可供后续块考虑。
<into>
块使用嵌套的<include>
和<exclude>
元素来声明内容。<application>
部分使用Ant风格的路径匹配来定义包含/排除表达式。<dependencies>
部分使用group:artifact[:version]
模式。它还提供了<includeModuleDependencies />
和<excludeModuleDependencies />
元素,这些元素可用于包含或排除本地模块依赖项。
如果没有定义<include>
,那么所有内容(未被先前的块声明的内容)都会被考虑进去。
如果没有定义<exclude>
,那么就不会应用任何排除规则。
从上面的<dependencies>
示例中,我们可以看到,第一个<into>
将为application.layer
声明所有的模块依赖项。下一个<into>
将为snapshot-dependencies
层声明所有的SNAPSHOT依赖项。最后一个<into>
将声明剩下的任何内容(在这种情况下,是指任何非SNAPSHOT的依赖项)为dependencies
层。
<application>
块有类似的规则。首先为spring-boot-loader
层声明org/springframework/boot/loader/**
的内容。然后为application
层声明任何剩余的类和资源。
注意:<into>
块的定义顺序通常与层的写入顺序不同。因此,必须始终包含<layerOrder>
元素,并且必须涵盖所有由<into>
块引用的层。
我们将使用分层特性来创建一个优化的Docker镜像。当您创建一个包含层索引文件的jar包时,spring-boot-jarmode-layertools jar
将被添加为您jar的依赖项。只要该jar在类路径上,您就可以在特殊模式下启动应用程序,该模式允许引导代码运行与您的应用程序完全不同的东西,例如,提取层的东西。
layertools
模式不能与包含启动脚本的完全可执行的Spring Boot归档文件一起使用。在构建打算与layertools
一起使用的jar文件时,应禁用启动脚本配置。
以下是如何以layertools
jar模式启动jar包:
$ java -Djarmode=layertools -jar my-app.jar
这将提供以下输出:
使用方法:
java -Djarmode=layertools -jar my-app.jar
可用命令:
list 列出可从jar中提取的层
extract 从jar中提取层以创建镜像
help 有关任何命令的帮助
extract
命令可用于轻松将应用程序拆分为要添加到Dockerfile的层。
以下是一个使用jarmode
的Dockerfile示例。
FROM eclipse-temurin:17-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM eclipse-temurin:17-jre
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.launch.JarLauncher"]
假设上述Dockerfile位于当前目录中,您的Docker镜像可以使用docker build命令构建,或者选择指定应用程序jar的路径,如下例所示:
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
这是一个多阶段的Dockerfile。builder阶段提取稍后需要的目录。每个COPY
命令都与jarmode
提取的层相关。
当然,Dockerfile可以在不使用jarmode
的情况下编写。您可以使用unzip
和mv
的某种组合将内容移动到正确的层,但jarmode
简化了这一过程。
第一阶段:builder
FROM eclipse-temurin:17-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM eclipse-temurin:17-jre as builder
:这行代码开始了第一阶段,命名为 builder
。它使用了一个包含 Java 17 JRE 的基础镜像 eclipse-temurin:17-jre
。WORKDIR application
:设置工作目录为 application
。ARG JAR_FILE=target/*.jar
:定义了一个参数 JAR_FILE
,默认值为 target/*.jar
,这意味着它会尝试复制 target
目录下的任何 JAR 文件。COPY ${JAR_FILE} application.jar
:将构建好的 JAR 文件复制到镜像的 application.jar
。RUN java -Djarmode=layertools -jar application.jar extract
:这行命令使用 Spring Boot 的 layertools
功能来解压 JAR 文件的不同层。允许将 JAR 文件分解为不同的层,以便于在 Docker 镜像中更有效地缓存和复用这些层。第二阶段:生产镜像
FROM eclipse-temurin:17-jre
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.launch.JarLauncher"]
FROM eclipse-temurin:17-jre
:这行代码开始了第二阶段(也是最终的生产镜像阶段),它同样使用了 eclipse-temurin:17-jre
作为基础镜像。WORKDIR application
:再次设置工作目录为 application
。COPY
指令都从 builder
阶段复制了之前通过 layertools extract
分解出来的不同层到当前阶段。这样做的好处是,如果这些层在未来的构建中没有变化,Docker 可以利用缓存机制,避免重复构建这些层,从而提高构建效率。
COPY --from=builder application/dependencies/ ./
:复制依赖项层。COPY --from=builder application/spring-boot-loader/ ./
:复制 Spring Boot 加载器层。COPY --from=builder application/snapshot-dependencies/ ./
:如果有快照依赖项,则复制它们。COPY --from=builder application/application/ ./
:复制应用程序本身的文件和资源。ENTRYPOINT ["java", "org.springframework.boot.loader.launch.JarLauncher"]
:设置容器的入口点,以便在容器启动时运行 Spring Boot 应用程序。通过这种方式,Dockerfile 利用了多阶段构建和 Spring Boot 的层工具来创建一个优化了大小和构建时间的 Docker 镜像。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。