共计 4358 个字符,预计需要花费 11 分钟才能阅读完成。
随着越来越多的组织转向容器和虚构服务器,Docker 正成为软件开发工作流程中一个更重要的局部。为此,Spring Boot 2.3 中最新的性能之中,提供了为 Spring Boot 应用程序创立 Docker 镜像的能力。
这篇文章的目标,就是为了给大家介绍如何为 Spring Boot 应用程序创立 Docker 镜像。
1. 传统 Docker 构建
应用 Spring Boot 构建 Docker 镜像的传统办法是应用 Dockerfile。上面是一个简略的例子:
FROM openjdk:8-jdk-alpine
EXPOSE 8080
ARG JAR_FILE=target/demo-app-1.0.0.jar
ADD ${JAR_FILE} app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
而后咱们能够应用 docker build 命令来创立 Docker
映像。这对大多数应用程序都很好,但也有一些毛病。
首先,咱们应用的是 Spring Boot
创立的 fat jar。这会影响启动工夫,尤其是在集装箱环境中。咱们能够通过增加 jar 文件的合成内容来节俭启动工夫。
其次,Docker 镜像是分层构建的。Spring Boot fat jar 的个性使得所有的利用程序代码和第三方库都放在一个层中。这意味着即便只有一行代码更改,也必须从新构建整个层。
通过在构建之前合成 jar,利用程序代码和第三方库各自取得本人的层。这样,咱们便能够利用 Docker 的缓存机制。当初,当某一行代码被更改时,只须要从新构建相应的层。
思考到这一点,让咱们看看 Spring Boot 如何改良创立 Docker 镜像的过程。
2. Buildpacks
BuildPacks 是一种提供框架和应用程序依赖性的工具。
例如,给定一个 Spring Boot fat jar,一个 buildpack 将为咱们提供 Java 运行时。这使咱们能够跳过 Dockerfile 并主动取得一个正当的 docker 镜像。
Spring Boot 包含对 bulidpacks 的 Maven 和 Gradle 反对。例如,应用 Maven 构建时,咱们将运行以下命令:
./mvnw spring-boot:build-image
咱们察看下一些相干的输入,看看产生了什么:
[INFO] Building jar: target/demo-0.0.1-SNAPSHOT.jar
...
[INFO] Building image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] > Pulling builder image 'gcr.io/paketo-buildpacks/builder:base-platform-api-0.3' 100%
...
[INFO] [creator] ===> DETECTING
[INFO] [creator] 5 of 15 buildpacks participating
[INFO] [creator] paketo-buildpacks/bellsoft-liberica 2.8.1
[INFO] [creator] paketo-buildpacks/executable-jar 1.2.8
[INFO] [creator] paketo-buildpacks/apache-tomcat 1.3.1
[INFO] [creator] paketo-buildpacks/dist-zip 1.3.6
[INFO] [creator] paketo-buildpacks/spring-boot 1.9.1
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
[INFO] Total time: 44.796 s
第一行显示咱们构建了规范的 fat jar,与其余典型的 maven 包一样。
下一行开始 Docker 映像构建。而后,看到这个 bulid 拉取了 packeto 构建器。
packeto 是基于云原生 bulidpacks 的实现。它负责剖析咱们的我的项目并确定所需的框架和库。在咱们的例子中,它确定咱们有一个 Spring Boot 我的项目并增加所需的构建包。
最初,咱们看到生成的 Docker 映像和总构建工夫。留神,在第一次构建时,花了相当多的工夫下载构建包并创立不同的层。
buildpacks 的一大特点是 Docker 映像是多层的。因而,如果咱们只更改利用程序代码,后续构建将更快:
...
[INFO] [creator] Reusing layer 'paketo-buildpacks/executable-jar:class-path'
[INFO] [creator] Reusing layer 'paketo-buildpacks/spring-boot:web-application-type'
...
[INFO] Successfully built image 'docker.io/library/demo:0.0.1-SNAPSHOT'
...
[INFO] Total time: 10.591 s
3. 层级 jar 包
在某些状况下,咱们可能不喜爱应用 bulidpacks ——兴许咱们的基础架构曾经绑定到另一个工具上,或者咱们曾经有了咱们想要从新应用的自定义 Dockerfiles。
基于这些起因,Spring Boot 还反对应用分层 jars 构建 Docker 映像。为了理解它的工作原理,让咱们看看一个典型的 Spring Boot fat jar 布局:
org/
springframework/
boot/
loader/
...
BOOT-INF/
classes/
...
lib/
...
fat jar 由 3 个次要区域组成:
- 启动 Spring 应用程序所需的疏导类
- 利用程序代码
- 第三方库
应用分层 jar,构造看起来很类似,然而咱们失去了一个新的 layers.idx 将 fat jar 中的每个目录映射到一个层的文件:
- "dependencies":
- "BOOT-INF/lib/"
- "spring-boot-loader":
- "org/"
- "snapshot-dependencies":
- "application":
- "BOOT-INF/classes/"
- "BOOT-INF/classpath.idx"
- "BOOT-INF/layers.idx"
- "META-INF/"
Out-of-the-box, Spring Boot provides four layers:
开箱即用,Spring Boot 提供 4 层:
- dependencies: 来自第三方的依赖
- snapshot-dependencies: 来自第三方的 snapshot 依赖
- resources: 动态资源
- application: 利用程序代码和资源(resources)
咱们的指标是将利用程序代码和第三方库搁置到层中,以反映它们更改的频率。
例如,利用程序代码可能是更改最频繁的代码,因而它有本人的层。此外,每一层都能够独立演变,只有当一层发生变化时,才会为它重建 Docker 镜像。
当初咱们理解了分层 jar 构造,接下来看看如何利用它来制作 Docker 映像。
3.1. 创立分层 jar
首先,咱们必须建设一个我的项目来创立一个分层的 jar。对于 Maven,则须要在 POM 的 Spring Boot plugin 局部增加一个新的配置:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
</plugin>
有了这个配置,Maven package 命令(包含它的其余依赖命令)将应用后面提到的四个默认层生成一个新的分层 jar。
3.2. 查看和提取分层
下一步,咱们须要从 jar 中提取层,这样 Docker 镜像能力领有正确的层。
要查看分层 jar 的任何层,能够运行以下命令:
java -Djarmode=layertools -jar demo-0.0.1.jar list
而后提取它们,运行命令:
java -Djarmode=layertools -jar demo-0.0.1.jar extract
3.3. 创立 Docker 映像
将这些层合并到 Docker 映像中的最简略办法是应用 Dockerfile:
FROM adoptopenjdk:11-jre-hotspot as builder
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM adoptopenjdk:11-jre-hotspot
COPY --from=builder dependencies/ ./
COPY --from=builder snapshot-dependencies/ ./
COPY --from=builder spring-boot-loader/ ./
COPY --from=builder application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
这个 Dockerfile 从 fat jar 中提取层,而后将每个层复制到 Docker 映像中。
每个 COPY 指令最终都会在 Docker 映像 中生成一个新层。
如果咱们构建这个 Dockerfile,咱们能够看到分层 jar 中的每个层都作为本人的层增加到 Docker 镜像中:
...
Step 6/10 : COPY --from=builder dependencies/ ./
---> 2c631b8f9993
Step 7/10 : COPY --from=builder snapshot-dependencies/ ./
---> 26e8ceb86b7d
Step 8/10 : COPY --from=builder spring-boot-loader/ ./
---> 6dd9eaddad7f
Step 9/10 : COPY --from=builder application/ ./
---> dc80cc00a655
...
4. 总结
在本文中,咱们学习了应用 Spring Boot 构建 Docker 映像的各种办法。
应用 buildpacks,咱们能够取得适合的 Docker 镜像,而无需模板或自定义配置。
或者,再多花点功夫,咱们就能够应用分层 jar 来取得一个更加定制的 Docker 镜像。
如果你感觉文章还不错,记得关注公众号:锅外的大佬
刘一手的博客