容器镜像

1. 高效的容器镜像

很容易将 Spring Boot 胖 jar 打包为 docker 映像。 但是,复制和运行 Docker 映像中的胖 jar 有各种缺点。 在不拆包的情况下运行一个胖罐时,总是会有一定的开销,在容器化环境中,这可能会很明显。 另一个问题是,将应用程序的代码及其所有依赖项放在 Docker 映像中的一层中是次优的。 由于重新编译代码的频率可能高于升级使用的 Spring Boot 版本,因此通常最好将内容分开一点。 如果你把 jar 文件放在应用程序类之前的层中,Docker 通常只需要更改最底层,就可以从它的缓存中获取其他文件。spring-doc.cadn.net.cn

1.1. 解压可执行 JAR

如果您从容器运行应用程序,则可以使用可执行的 jar,但分解它并以不同的方式运行它通常也是一个优势。 某些 PaaS 实现也可能选择在存档运行之前解压缩它们。 例如,Cloud Foundry 就是这样运作的。 运行解压存档的一种方法是启动相应的Starters,如下所示:spring-doc.cadn.net.cn

$ jar -xf myapp.jar
$ java org.springframework.boot.loader.JarLauncher

这实际上在启动时(取决于 jar 的大小)比从未爆炸的存档运行要快一些。 在运行时,您不应期望有任何差异。spring-doc.cadn.net.cn

解压 jar 文件后,您还可以通过使用其“自然”主方法而不是JarLauncher.例如:spring-doc.cadn.net.cn

$ jar -xf myapp.jar
$ java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication
使用JarLauncher在应用程序的 main 方法上,具有可预测的类路径顺序的额外好处。 该罐子包含一个classpath.idx文件,该文件由JarLauncher构建类路径时。

1.2. 分层 Docker 镜像

为了更轻松地创建优化的 Docker 镜像,Spring Boot 支持向 jar 添加层索引文件。 它提供了层的列表以及应包含在其中的罐子部分。 索引中的层列表根据将层添加到 Docker/OCI 映像的顺序进行排序。 开箱即用,支持以下层:spring-doc.cadn.net.cn

下面显示了一个示例layers.idx文件:spring-doc.cadn.net.cn

- "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-doc.cadn.net.cn

Spring Boot 还支持在layers.idx.spring-doc.cadn.net.cn

对于 Maven,请参阅打包分层 jar 或 war 部分,了解有关将层索引添加到存档的更多详细信息。 对于 Gradle,请参阅 Gradle 插件文档中的打包分层 jar 或 war 部分spring-doc.cadn.net.cn

2. Docker文件

虽然只需在 Dockerfile 中插入几行即可将 Spring Boot 胖 jar 转换为 docker 映像,但我们将使用分层功能来创建优化的 docker 映像。 当您创建包含 layers 索引文件的 jar 时,spring-boot-jarmode-layertoolsjar 将作为依赖项添加到您的 jar 中。 在类路径上使用这个 jar,您可以在一种特殊模式下启动您的应用程序,该模式允许引导代码运行与您的应用程序完全不同的东西,例如,提取层的东西。spring-doc.cadn.net.cn

layertoolsmode 不能与包含启动脚本的完全可执行的 Spring Boot 存档一起使用。 在构建要与layertools.

以下是如何使用layertoolsjar 模式:spring-doc.cadn.net.cn

$ java -Djarmode=layertools -jar my-app.jar

这将提供以下输出:spring-doc.cadn.net.cn

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.spring-doc.cadn.net.cn

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 镜像可以使用docker build .,或选择性地指定应用程序 jar 的路径,如以下示例所示:spring-doc.cadn.net.cn

$ docker build --build-arg JAR_FILE=path/to/myapp.jar .

这是一个多阶段的 dockerfile。 构建器阶段提取稍后需要的目录。 每个COPY命令与 jarmode 提取的层相关。spring-doc.cadn.net.cn

当然,可以在不使用 jarmode 的情况下编写 Dockerfile。 您可以使用以下几种组合unzipmv将内容移动到正确的层,但 jarmode 简化了这一点。spring-doc.cadn.net.cn

3. 云原生 Buildpack

Dockerfile 只是构建 docker 镜像的一种方法。 构建 docker 镜像的另一种方法是直接从 Maven 或 Gradle 插件使用构建包。 如果您曾经使用过 Cloud Foundry 或 Heroku 等应用程序平台,那么您可能使用过 buildpack。 Buildpack 是平台的一部分,它获取您的应用程序并将其转换为平台可以实际运行的东西。 例如,Cloud Foundry 的 Java buildpack 会注意到您正在推送.jar文件并自动添加相关的 JRE。spring-doc.cadn.net.cn

借助云原生 Buildpack,您可以创建可在任何地方运行的 Docker 兼容映像。 Spring Boot 包括直接对 Maven 和 Gradle 的 buildpack 支持。 这意味着您只需键入一个命令,即可快速将合理的映像导入本地运行的 Docker 守护进程中。spring-doc.cadn.net.cn

请参阅有关如何将构建包与 MavenGradle 一起使用的各个插件文档。spring-doc.cadn.net.cn

Paketo Spring Boot buildpack 也已更新以支持layers.idx文件,因此应用于它的任何自定义都将反映在 Buildpack 创建的映像中。
为了实现可重现的构建和容器映像缓存,Buildpack 可以作应用程序资源元数据(例如文件“上次修改”信息)。 应确保应用程序在运行时不依赖于该元数据。 Spring Boot 可以在提供静态资源时使用该信息,但可以使用spring.web.resources.cache.use-last-modified

4. 接下来要读什么

了解如何构建高效的容器映像后,您可以阅读有关将应用程序部署到云平台(例如 Kubernetes)的信息。spring-doc.cadn.net.cn