Spring Boot 分层构建容器镜像官方文档学习笔记

稍微查了下发现分层构建容器镜像是从 2.3.x 就支持了,以“spring boot 分层 构建”为关键词也能找到不少中文资料,但还是先从官方文档看起吧(虽然英语渣看得真的很痛苦)
不用指望翻译的质量了,基本是机翻+简(负)单(面)润色,翻译一遍确保我看英文的时候不会因为看不懂就下意识跳过一些东西导致整篇看下来其实啥也没看。
并且由于整篇东西是 notion 直接复制过来的,所以格式可能也有点问题。我会粗略修正一遍但也可能有所遗漏。
言归正传了:

官方文档

Spring Boot applications can be containerized using Dockerfiles, or by using Cloud Native Buildpacks to create optimized docker compatible container images that you can run anywhere.

Spring Boot 的应用能够使用 Dockfiles 容器化,或者通过使用云原生 BuildPacks 来创建可以在任何地方运行的优化过的 docker 兼容容器镜像。

1. Efficient container images
It is easily possible to package a Spring Boot fat jar as a docker image. However, there are various downsides to copying and running the fat jar as is in the docker image. There’s always a certain amount of overhead when running a fat 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.

  1. 高效的容器镜像
    把一个臃肿的 Spring Boot jar 包打包成一个 docker 镜像是很简单的。然而,复制以及运行这种包含臃肿 jar 包的镜像有着非常多的缺点。运行一个没有解压过的臃肿 jar 包总会有一定量的开销,并且在一个容器化的环境中这将非常明显。另一个问题是将您的应用的代码和它全部的依赖放在 Docker 镜像的同一层中并不是最优的。一般来说您重新编译代码的频率会比您升级所用的 Spring Boot 的版本的频率要高,因此通常情况下,把相关事物分离会比较好。如果您将 jar 文件放在您的应用程序类之前的层中,Docker 通常只需要更改最底层并且可以从它的缓存中获取其他内容。

1.1. Unpacking the fat jar
If you are running your application from a container, you can use an executable jar, but it is also often an advantage to explode it and run it in a different way. Certain PaaS implementations may also choose to unpack archives before they run. For example, Cloud Foundry operates this way. One way to run an unpacked archive is by starting the appropriate launcher, as follows:

1.1. 解压臃肿 jar 包
如果你要从一个容器中运行你的应用程序,可以使用一个可执行的 jar 包,但是将其分解并用一种不同的方式运行它通常也是一种优势。某些 Paas 实现可能也会选择在运行之前解压归档文件。比如,Cloud Foundry 就是这么做的。运行未打包的归档文件的一种方式是启动适当的启动程序,如下所示:

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

This is actually slightly faster on startup (depending on the size of the jar) than running from an unexploded archive. At runtime you should not expect any differences.

这样实际上在启动时比从未分解的归档文件运行要稍快(取决于 jar 的大小)。但在运行时,您不应当期待能发现什么不同。

Once you have unpacked the jar file, you can also get an extra boost to startup time by running the app with its "natural" main method instead of the JarLauncher. For example:

一旦您有了解压过的 jar 包文件,你可以通过应用程序的 “natural” 主方法而不是 JarLauncher 来运行应用来进一步缩短启动时间。如下所示:

jar -xf myapp.jar
java -cp BOOT-INF/classes:BOOT-INF/lib/* com.example.MyApplication

Note
Using the JarLauncher over the application’s main method has the added benefit of a predictable classpath order. The jar contains a classpath.idx file which is used by the JarLauncher when constructing the classpath.

在应用程序的主方法上使用 JarLauncher 有一个额外的好处:类路径的顺序是可预测的。jar 包包含一个 classpath.idx 文件,当 JarLauncher 构造类路径时会使用该文件。

1.2. Layering Docker Images
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)

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

1.2. Docker 镜像分层

为了使得创建优化过的 Docker 镜像更方便,Spring Boot 支持在 jar 包中增加一个分层索引文件。这个文件提供了一个分层列表以及各层应当包含的 jar 包的部分。该索引中的分层列表是根据各层添加至 Docker/OCI 镜像的顺序排列的。开箱即用,支持以下分层:

  • 依赖(定期发布的依赖项)
  • spring-boot-loader(在 org/springframework/boot/loader 目录下的所有文件)
  • 快照依赖(快照版本的依赖项)
  • 应用程序(应用程序的类文件和资源文件)

下面展示了一个 layers.idx 文件的示例:

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

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.

这种分层旨在根据代码在应用程序多次构建之间发生更改的可能性大小将其分离开。库代码不太可能在多次构建中发生变化,所以将其放置在自己的分层中以允许工具重用缓存中的分层。应用代码在多次构建中最可能发生改变,因此它被隔离在单独的层中。

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

Spring Boot 也支持在 layers.idx 的支持下对 war 包文件进行分层。

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.

对 Maven 而言,向归档文件内添加分层索引的更多细节参阅”打包分层的 jar 包或 war 包“部分。对 Gradle 而言,参阅 Gradle 插件文档的”打包分层的 jar 包或 war 包“部分。

2. Dockerfiles
While it is possible to convert a Spring Boot fat jar into a docker image with just a few lines in the Dockerfile, we will use the layering feature to create an optimized docker image. When you create a jar containing the layers index file, the spring-boot-jarmode-layertools jar will be added as a dependency to your jar. With this jar on the classpath, you can launch your application in a special mode which allows the bootstrap code to run something entirely different from your application, for example, something that extracts the layers.

  1. Dockerfiles

虽然通过 Dockerfile 里的几行命令就可以将一个 Spirng Boot 臃肿 jar 包转换成 docker 镜像,但我们将使用分层特性创建一个优化过的 docker 镜像。当您创建一个包含分层索引文件的 jar 包时,spring-boot-jarmode-layertools 的 jar 包将被作为依赖项添加到您的 jar 包中。通过类路径上的这个 jar 包,您可以在特殊模式下启动您的程序:该模式允许引导代码运行一些与您的代码完全不同的东西,比如能够提取分层信息的程序。

Caution
The layertools mode can not be used with a fully executable Spring Boot archive that includes a launch script. Disable launch script configuration when building a jar file that is intended to be used with layertools.

注意:

layertools 模式不能与包含启动脚本的完全可执行 Spring Boot 归档文件一起使用。在要构建用于 layertools 的 jar 包文件时禁用启动脚本配置。

Here's how you can launch your jar with a layertools jar mode:

这里展示了你怎么通过 layertools 模式启动你的 jar 包

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

This will provide the following output:

这会提供以下输出信息:

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

The extract command can be used to easily split the application into layers to be added to the dockerfile. Here is an example of a Dockerfile using jarmode.

使用 extract 命令可以简单的将应用程序拆分成各个要被添加至 dockerfile 的分层。下面是一个使用 jarmode 的 Dockerfile 示例:

FROM adoptopenjdk:11-jre-hotspot as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk:11-jre-hotspot
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"]

Assuming the above Dockerfile is in the current directory, your docker image can be built with docker build ., or optionally specifying the path to your application jar, as shown in the following example:

假设上面的 Dockerfile 文件位于当前目录,您可以使用 docker build . 命令构建 docker 镜像,或者可以指定应用程序的 jar 包路径,如下例所示:

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

This is a multi-stage dockerfile. The builder stage extracts the directories that are needed later. Each of the COPY commands relates to the layers extracted by the jarmode.
Of course, a Dockerfile can be written without using the jarmode. You can use some combination of unzip and mv to move things to the right layer but jarmode simplifies that.

这是一个多阶段的 dockerfile 。builder 阶段提取下一个阶段所需要的目录。每一个 COPY 命令都与 jarmode 提取的分层相关。

当然,也可以在不使用 jarmode 的情况下编写 Dockerfile 文件。您可以使用一些 unzipmv 命令的组合来将文件移动到对应的分层,但是 jarmode 简化了这一过程。

  1. Cloud Native Buildpacks
    Dockerfiles are just one way to build docker images. Another way to build docker images is directly from your Maven or Gradle plugin, using buildpacks. If you’ve ever used an application platform such as Cloud Foundry or Heroku then you’ve probably used a buildpack. Buildpacks are the part of the platform that takes your application and converts it into something that the platform can actually run. For example, Cloud Foundry’s Java buildpack will notice that you’re pushing a .jar file and automatically add a relevant JRE.

Dockerfiles 只是构建 docker 镜像的方法之一。而另一种方法是使用构建包直接从您的 Maven 或 Gradle 插件构建。如果您曾经使用过 Cloud Foundry 或者 Heroku 之类的应用平台,那么您可能使用过 buildpack。Buildpack 是平台的一部分,它获取您的应用并且将其转换为平台实际运行的东西。例如,Cloud Foundry 的 Java buildpack 会在您推送一个 .jar 文件的时候自动添加相关的 JRE。

With Cloud Native Buildpacks, you can create Docker compatible images that you can run anywhere. Spring Boot includes buildpack support directly for both Maven and Gradle. This means you can just type a single command and quickly get a sensible image into your locally running Docker daemon.
See the individual plugin documentation on how to use buildpacks with Maven and Gradle.

您可以通过使用 Cloud Native Buildpack 创建能在任何地方运行的 Docker 兼容镜像。Spring Boot 包含对 Maven 以及 Gradle 的 buildpack 的直接支持。这意味着您可以仅仅通过输入一条命令将一个合理的镜像文件放入本地运行的 Docker daemon 中。

有关如何在 Maven 和 Gradle 中使用 buildpack ,请参阅相关的文档。

Note
The Paketo Spring Boot buildpack has also been updated to support the layers.idx file so any customization that is applied to it will be reflected in the image created by the buildpack.

Paketo Spring Boot buildpack 也已经更新以支持 layers.idx 文件,因此任何应用于它的任何自定义设置都将反映在 buildpack 创建的镜像中。

Note
In order to achieve reproducible builds and container image caching, Buildpacks can manipulate the application resources metadata (such as the file "last modified" information). You should ensure that your application does not rely on that metadata at runtime. Spring Boot can use that information when serving static resources, but this can be disabled with spring.web.resources.cache.use-last-modified

为了实现可重复的 build 以及容器镜像缓存,Buildpack 可以操作应用程序的资源元数据(比如文件的“上次修改”信息)。您应该确保应用运行时不依赖于这类元数据。Spring Boot 会在服务静态资源时使用这些信息,但可以通过spring.web.resources.cache.use-last-modified 来设置禁用。

4. What to Read Next
Once you’ve learned how to build efficient container images, you can read about deploying applications to a cloud platform, such as Kubernetes.

一旦您了解了如何构建高效的容器镜像,您就可以阅读有关将应用程序部署到云平台(如 Kubernetes)的内容。

posted @ 2021-12-06 22:58  C_BC  阅读(715)  评论(0编辑  收藏  举报