Efficient Container Images

将 Spring Boot uber jar 打包为 docker 映像非常简单。然而,按原样复制和运行 uber jar 在 docker 映像中有多种弊端。在不将其解包的情况下运行 uber jar 总会出现一定程度的开销,而在容器化环境中这可能会很明显。另一个问题是将你的应用程序代码及其所有依赖项放置在 Docker 映像中的一个层中不是最优的。由于你重新编译代码的频率可能高于你升级所用 Spring Boot 版本的频率,因此通常最好将内容分得更开。如果你在应用程序类之前将 jar 文件放置在层中,则 Docker 通常仅需更改最底层,即可从其缓存中选取其他内容。

It is easily possible to package a Spring Boot uber jar as a docker image. However, there are various downsides to copying and running the uber jar as is in the docker image. There’s always a certain amount of overhead when running a uber jar without unpacking it, and in a containerized environment this can be noticeable. The other issue is that putting your application’s code and all its dependencies in one layer in the Docker image is sub-optimal. Since you probably recompile your code more often than you upgrade the version of Spring Boot you use, it’s often better to separate things a bit more. If you put jar files in the layer before your application classes, Docker often only needs to change the very bottom layer and can pick others up from its cache.

Layering Docker Images

为了更轻松地创建优化的 Docker 映像,Spring Boot 支持将层索引文件添加到 jar 中。它提供了一系列层和应当包含在其中的 jar 部分。索引中的层列表是根据层应当添加到 Docker/OCI 映像的顺序排列的。开箱即用情况下,支持以下层:

To make it easier to create optimized Docker images, Spring Boot supports adding a layer index file to the jar. It provides a list of layers and the parts of the jar that should be contained within them. The list of layers in the index is ordered based on the order in which the layers should be added to the Docker/OCI image. Out-of-the-box, the following layers are supported:

  • dependencies (for regular released dependencies)

  • spring-boot-loader (for everything under org/springframework/boot/loader)

  • snapshot-dependencies (for snapshot dependencies)

  • application (for application classes and resources)

以下显示了 layers.idx 文件示例:

The following shows an example of a layers.idx file:

- "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

这种分层旨在根据代码在应用程序构建之间发生变化的可能性对代码进行分离。库代码在不同构建之间的变化可能性较小,因此将其放置在其自身的层中,以允许工具从缓存中重新使用这些层。应用程序代码在不同构建之间的变化可能性较高,因此将其隔离在单独的层中。

This layering is designed to separate code based on how likely it is to change between application builds. Library code is less likely to change between builds, so it is placed in its own layers to allow tooling to re-use the layers from cache. Application code is more likely to change between builds so it is isolated in a separate layer.

借助 layers.idx 的帮助,Spring Boot 还支持 war 文件的分层。

Spring Boot also supports layering for war files with the help of a layers.idx.

对于 Maven,请参阅 packaging layered jar or war section 以了解有关向归档添加层索引的更多详细信息。对于 Gradle,请参阅 Gradle 插件文档的 packaging layered jar or war section

For Maven, see the packaging layered jar or war section for more details on adding a layer index to the archive. For Gradle, see the packaging layered jar or war section of the Gradle plugin documentation.