高效的容器镜像

将 Spring Boot uber jar 打包成 Docker 镜像非常容易。但是,将 uber jar 复制到 Docker 镜像中并直接运行存在一些缺点。在不解压缩的情况下运行 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

这种分层设计旨在根据代码在应用程序构建之间发生变化的可能性进行分离。库代码在构建之间不太可能发生变化,因此它被放置在自己的层中,以允许工具从缓存中重新使用这些层。应用程序代码在构建之间更有可能发生变化,因此它被隔离在单独的层中。

Spring Boot 还支持使用 layers.idx 对 war 文件进行分层。

对于 Maven,请参阅 打包分层 jar 或 war 部分,以详细了解如何将层索引添加到存档中。对于 Gradle,请参阅 打包分层 jar 或 war 部分 的 Gradle 插件文档。