高效的容器镜像
很容易将 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,请参阅 Gradle 插件文档中的分层 JAR 或 WAR 打包部分。