容器镜像
1. 高效的容器镜像
很容易将 Spring Boot 胖 jar 打包为 docker 映像。 但是,复制和运行 Docker 镜像中的 fat jar 存在各种缺点。 在不解包的情况下运行 fat jar 时,总会有一定量的开销,在容器化环境中,这可能会很明显。 另一个问题是,将应用程序的代码及其所有依赖项放在 Docker 映像的一层中是次优的。 由于您可能更频繁地重新编译代码,而不是升级您使用的 Spring Boot 版本,因此通常最好将内容分开更多。 如果你把 jar 文件放在应用程序类之前的层中,Docker 通常只需要改变最底层,就可以从它的缓存中获取其他文件。
1.1. 对 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
.
对于 Maven,请参阅打包分层 jar 或 war 部分,以了解有关向存档添加层索引的更多详细信息。 对于 Gradle,请参阅 Gradle 插件文档的打包分层 jar 或 war 部分。
2. Dockerfile 文件
虽然只需在 Dockerfile 中编写几行代码就可以将 Spring Boot fat jar 转换为 docker 映像,但我们将使用分层功能来创建优化的 docker 映像。
当您创建包含 layers 索引文件的 jar 时,spring-boot-jarmode-layertools
jar 将作为依赖项添加到您的 jar 中。
在 Classpath 上使用此 jar,您可以以特殊模式启动应用程序,该模式允许引导代码运行与应用程序完全不同的东西,例如,提取层的东西。
这layertools mode 不能与包含启动脚本的完全可执行的 Spring Boot 存档一起使用。
在构建旨在用于的 jar 文件时禁用启动脚本配置layertools . |
以下是使用layertools
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
.
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.JarLauncher"]
假设上述情况Dockerfile
位于当前目录中,则可以使用 Docker 镜像docker build .
,或者选择指定应用程序 jar 的路径,如以下示例所示:
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
这是一个多阶段 dockerfile。
builder 阶段将提取稍后需要的目录。
每个COPY
命令与 JarMode 提取的图层相关。
当然,可以在不使用 jarmode 的情况下编写 Dockerfile。
您可以使用unzip
和mv
将内容移动到正确的图层,但 JarMode 简化了此作。
3. 云原生 Buildpack
Dockerfile 只是构建 Docker 镜像的一种方式。
构建 docker 镜像的另一种方法是直接从 Maven 或 Gradle 插件使用 buildpacks。
如果您曾经使用过 Cloud Foundry 或 Heroku 等应用程序平台,那么您可能使用过 buildpack。
Buildpack 是平台的一部分,它获取您的应用程序并将其转换为平台可以实际运行的内容。
例如,Cloud Foundry 的 Java buildpack 会注意到您正在推送一个.jar
文件并自动添加相关的 JRE。
使用 Cloud Native Buildpacks,您可以创建可在任何地方运行的 Docker 兼容映像。 Spring Boot 直接包括 Maven 和 Gradle 的 buildpack 支持。 这意味着您只需键入一个命令,即可快速将合理的映像获取到本地运行的 Docker 守护程序中。
Paketo Spring Boot buildpack 支持layers.idx 文件,因此应用于它的任何自定义都将反映在 buildpack 创建的镜像中。 |
为了实现可重现的构建和容器镜像缓存,Buildpack 可以作应用程序资源元数据(例如文件的“last modified”信息)。
您应该确保您的应用程序在运行时不依赖该元数据。
Spring Boot 可以在提供静态资源时使用该信息,但这可以通过spring.web.resources.cache.use-last-modified . |
4. 下一步阅读什么
了解如何构建高效的容器映像后,您可以阅读有关将应用程序部署到云平台(如 Kubernetes)的信息。