随着越来越多的组织转向容器和虚构服务器,Docker正成为软件开发工作流程中一个更重要的局部。为此,Spring Boot 2.3中最新的性能之中,提供了为Spring Boot应用程序创立 Docker 镜像的能力。
这篇文章的目标,就是为了给大家介绍如何为 Spring Boot 应用程序创立 Docker 镜像。
1. 传统Docker构建
应用Spring Boot 构建 Docker 镜像的传统办法是应用 Dockerfile 。上面是一个简略的例子:
FROM openjdk:8-jdk-alpineEXPOSE 8080ARG JAR_FILE=target/demo-app-1.0.0.jarADD ${JAR_FILE} app.jarENTRYPOINT ["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 builderARG JAR_FILE=target/*.jarCOPY ${JAR_FILE} application.jarRUN java -Djarmode=layertools -jar application.jar extract FROM adoptopenjdk:11-jre-hotspotCOPY --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/ ./ ---> 2c631b8f9993Step 7/10 : COPY --from=builder snapshot-dependencies/ ./ ---> 26e8ceb86b7dStep 8/10 : COPY --from=builder spring-boot-loader/ ./ ---> 6dd9eaddad7fStep 9/10 : COPY --from=builder application/ ./ ---> dc80cc00a655...
4.总结
在本文中,咱们学习了应用 Spring Boot 构建 Docker 映像的各种办法。
应用 buildpacks,咱们能够取得适合的Docker镜像,而无需模板或自定义配置。
或者,再多花点功夫,咱们就能够应用分层 jar 来取得一个更加定制的Docker镜像。
如果你感觉文章还不错,记得关注公众号: 锅外的大佬
刘一手的博客