跳到主要内容

高效的容器镜像

DeepSeek V3 中英对照 Efficient Container Images

将 Spring Boot 的 uber jar 打包为 Docker 镜像是非常容易的。然而,直接在 Docker 镜像中复制并运行 uber jar 会带来各种缺点。在不解压的情况下运行 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
yaml

这种分层设计旨在根据代码在应用程序构建之间变化的可能性进行分离。库代码在构建之间变化的可能性较小,因此它被放置在自己的层中,以便工具可以从缓存中重用这些层。应用程序代码在构建之间变化的可能性较大,因此它被隔离在一个单独的层中。

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

对于 Maven,请参阅打包分层 jar 或 war 部分以了解有关向归档添加层索引的更多详细信息。对于 Gradle,请参阅 Gradle 插件文档中的打包分层 jar 或 war 部分