随着越来越多的组织转向容器和虚构服务器,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镜像。
如果你感觉文章还不错,记得关注公众号: 锅外的大佬
刘一手的博客
发表回复