Spring Boot应用程序可以 使用 Dockerfiles 进行容器化,也可以 使用 Cloud Native Buildpacks 创建可以在任何地方运行的兼容 Docker 容器镜像.
1. 高效的容器镜像
可以很容易地将 Spring Boot 的 fat jar 打包为 docker 镜像. 但是,像在 docker 镜像中一样,复制和运行 fat jar 还有很多弊端. 在不打包的情况下运行 fat jar 时,总会有一定的开销,在容器化环境中,这很明显. 另一个问题是,将应用程序的代码及其所有依赖放在 Docker 镜像 的一层中是次优的. 由于重新编译代码的频率可能比升级所用 Spring Boot 的版本的频率高,因此最好将代码分开一些. 如果将 jar 文件放在应用程序类之前的层中,则 Docker 通常只需要更改最底层即可从其缓存中获取其他文件.
1.1. 解压 fat jar
您可以使用可执行 jar 在容器中运行,但以不同的方式去解压和运行它通常也是一个优势。 某些 PaaS 实现也可能会选择在运行前解压缩。 例如,Cloud Foundry 就是这样运作的。 解压的一种方法是启动适当的启动器,如下所示:
$ jar -xf myapp.jar
$ java org.springframework.boot.loader.JarLauncher
这实际上在启动时(取决于 jar 的大小)比从未分解的存档中运行要快一些。 在运行时,您不应期望有任何差异。
一旦你解压了 jar 文件,你还可以通过使用它的 "natural" 主方法而不是 JarLauncher
运行应用程序来获得额外的启动时间。 例如:
$ jar -xf myapp.jar
$ java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication
在应用程序的 main 方法上使用 JarLauncher 具有可预测的类路径顺序的额外好处.jar 包含一个 classpath.idx 文件,JarLauncher 在构建类路径时使用该文件。
|
1.2. 分层 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/JarLauncher.class
- org/springframework/boot/loader/jar/JarEntry.class
- "snapshot-dependencies":
- BOOT-INF/lib/library3-SNAPSHOT.jar
- "application":
- META-INF/MANIFEST.MF
- BOOT-INF/classes/a/b/C.class
此分层旨在根据应用程序构建之间更改的可能性来分离代码. 库代码不太可能在内部版本之间进行更改,因此将其放置在自己的层中,以允许工具重新使用缓存中的层. 应用程序代码更可能在内部版本之间进行更改,因此将其隔离在单独的层中.
Spring Boot 还支持在 layers.idx
的帮助下对 war 文件进行分层。
对于 Maven,请参阅 packaging layered jars section ,以获取有关在 jar 中添加层索引的更多详细信息. 对于 Gradle,请参阅 Gradle 插件文档的 packaging layered jars section.
2. Dockerfiles
虽然可以在 Dockerfile 中仅几行就将 Spring Boot jar 转换为 docker 镜像,但我们将使用 分层功能 来创建优化的 docker 镜像. 当您创建一个包含 layers 索引文件的 jar 时,spring-boot-jarmode-layertools
jar 将作为依赖添加到您的 jar 中. 将此 jar 放在类路径上,您可以在特殊模式下启动应用程序,该模式允许引导代码运行与应用程序完全不同的内容,例如,提取层的内容.
layertools 模式不能与包含启动脚本的完全可执行的 fully executable Spring Boot archive 一起使用.在构建一个打算与 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 的示例.
FROM eclipse-temurin:11-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:11-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.JarLauncher"]
假设上述 Dockerfile
位于当前目录中,则可以使用 docker build
.生成您的 docker 镜像,或者可以选择指定应用程序 jar 的路径,如以下示例所示:
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
这是一个多阶段的 dockerfile. 构建器阶段提取以后需要的目录. 每个 COPY
命令都与 jarmode 提取的层有关.
当然,无需使用 jarmode 即可编写 Dockerfile
. 您可以使用 unzip
和 mv
的某种组合将内容移至正确的层,而 jarmode 简化了这一点.
3. Cloud Native Buildpacks
Dockerfiles 只是构建 Docker 镜像的一种方式. 构建 docker 镜像的另一种方法是直接从您的 Maven 或 Gradle 插件中使用 buildpacks. 如果您曾经使用过 Cloud Foundry 或 Heroku 等应用程序平台,那么您可能已经使用了一个 buildpack. Buildpacks 是平台的一部分,可接收您的应用程序并将其转换为平台可以实际运行的内容. 例如,Cloud Foundry 的 Java buildpack 将注意到您正在推送 .jar
文件并自动添加相关的 JRE.
借助 Cloud Native Buildpacks,您可以创建可在任何地方运行的 Docker 兼容镜像. Spring Boot 直接支持 Maven 和 Gradle 的 buildpack. 这意味着您只需输入一个命令,即可将明智的镜像快速地导入本地运行的Docker 守护程序.
Paketo Spring Boot buildpack 也已更新,以支持 layers.idx 文件,因此,对其应用的任何自定义都将反映在 buildpack 创建的镜像中.
|
为了实现可重复构建和容器映像缓存,Buildpacks 可以操作应用程序资源元数据(例如文件 "last modified" 信息)。您应该确保应用程序在运行时不依赖于该元数据。Spring Boot 可以在提供静态资源时使用这些信息,但是可以用 spring.web.resources.cache.use-last-modified 禁用这些信息.
|
4. 下一步
一旦你学会了如何构建高效的容器镜像,你可以阅读 将应用部署到云平台,比如 Kubernetes。