https://docs.spring.io/spring-boot/docs/3.2.0/reference/htmlsingle/#container-images
Spring Boot应用程序可以通过Dockerfile进行容器化,或者使用Cloud Native Buildpacks创建优化的、与Docker兼容的容器镜像,你可以在任何地方运行这些镜像。
高效的容器镜像
将Spring Boot的uber jar(指一个包含项目所有依赖的单一jar文)打包为Docker镜像非常容易。但是,在Docker镜像中复制并运行uber jar存在多种缺点。在不解压的情况下运行uber jar总是会产生一定的开销,在容器化环境中,这可能会很明显。另一个问题是,将应用程序的代码及其所有依赖项放在Docker镜像的一个层中不是最佳选择。由于你可能经常重新编译代码,而升级使用的Spring Boot版本的频率较低,因此通常最好将事物分开一些。如果将jar文件放在应用程序类之前的层中,Docker通常只需要更改最底层的层,并可以从其缓存中获取其它层。
Docker镜像分层
为了使创建优化的Docker镜像变得更加简单,Spring Boot支持向jar文件添加一个分层索引文件。这个文件提供了层的列表以及应该包含在这些层中的jar的部分。索引中层的列表是基于应该将层添加到Docker/OCI镜像的顺序进行排序的。开箱即用,支持以下层:
dependencies
(用于常规发布的依赖项)spring-boot-loader
(用于org/springframework/boot/loader
下的所有内容)snapshot-dependencies
(用于快照依赖项)application
(用于应用程序类和资源)
以下是一个layers.idx
文件的示例:
- "dependencies":
- BOOT-INF/lib/library1.jar
- BOOT-INF/lib/library2.jar
- "spring-boot-loader":
- org/springframework/boot/loader/launch/JarLauncher.class
- ... <other classes>
- "snapshot-dependencies":
- BOOT-INF/lib/library3-SNAPSHOT.jar
- "application":
- META-INF/MANIFEST.MF
- BOOT-INF/classes/a/b/C.class
这种分层设计旨在根据代码在应用程序构建之间更改的可能性来分离代码。库代码在构建之间不太可能更改,因此它被放置在自己的层中,以允许工具从缓存中重用这些层。应用程序代码在构建之间更有可能更改,因此它被隔离在单独的层中。
在layers.idx
的帮助下,Spring Boot还支持对war文件进行分层。
Dockerfile
尽管在Dockerfile中只需几行就可以将Spring Boot的uber jar转换为docker镜像,但将使用分层功能来创建一个优化的docker镜像。当你创建一个包含分层索引文件的jar时,spring-boot-jarmode-layertools
jar将作为你的jar的依赖项被添加。当此jar在类路径上时,你可以以特殊模式启动你的应用程序,这允许引导代码运行与你的应用程序完全不同的内容,例如,提取各层的内容。
注意:当使用包含启动脚本的完全可执行的Spring Boot归档文件时,不能使用layertools
模式。在构建打算与layertools
一起使用的jar文件时,请禁用启动脚本配置。
这是你可以使用带有layertools
jar模式的jar来启动应用程序的方式:
$ java -Djarmode=layertools -jar my-app.jar
这将会产生以下输出:
Usage:
java -Djarmode=layertools -jar my-app.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
extract
命令可用于轻松将应用程序拆分为多个层,以便将其添加到dockerfile中。下面是一个使用jarmode
的Dockerfile示例:
假设上述Dockerfile
位于当前目录中,你可以使用docker build .
命令来构建你的Docker镜像,或者可以选择性地指定你的应用程序jar文件的路径,如下例所示:
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
这是一个多阶段的Dockerfile。构建阶段提取了稍后所需的目录。每个COPY
命令都与通过jarmode提取的层相关。
当然,Dockerfile也可以在不使用jarmode的情况下编写。你可以使用unzip
和mv
的某种组合将东西移到正确的层,但jarmode简化了这一过程。
Cloud Native Buildpacks(云原生构建包)
Dockerfile只是构建Docker镜像的一种方式。另一种构建Docker镜像的方式是直接通过Maven或Gradle插件使用构建包(buildpacks)。如果你曾经使用过Cloud Foundry或Heroku等应用程序平台,那么你可能已经使用过构建包。构建包是平台的一部分,它负责将你的应用程序转换为平台可以实际运行的程序。例如,Cloud Foundry的Java构建包会注意到你正在推送一个.jar
文件,并自动添加相关的JRE。
通过Cloud Native Buildpacks,你可以创建与Docker兼容的镜像,可以在任何地方运行。Spring Boot直接为Maven和Gradle提供了构建包支持。这意味着你只需输入一个命令,就可以快速将合理的镜像推送到本地运行的Docker守护程序。
注意:Paketo Spring Boot构建包支持layers.idx
文件,因此对该文件进行的任何自定义都将在构建包创建的镜像中反映出来。
注意:为了实现可重复构建和容器镜像缓存,构建包可以操作应用程序资源的元数据(如文件的“最后修改”信息)。你应该确保你的应用程序在运行时不会依赖这些元数据。Spring Boot在提供静态资源时可以使用这些信息,但这可以通过spring.web.resources.cache.use-last-modified
来禁用。