目录
- 一. 概述
- 二. 常规多阶段构建镜像
- 三. 使用 buildkit 构建镜像
- 四. 使用依赖分层的方式构建镜像
- 五. 在 buildkit 构建期间使用卷挂载
- 六. 使用 maven 守护进程构建镜像
- 七. 结论
- 参考文章
一. 概述
本文将通过如下几个方式来构建 docker 镜像,通过记录每种方式的构建时间,从而得到在 docker 中构建 maven 项目最快的方式:
- 常规多阶段构建镜像
- 使用 buildkit 构建镜像
- 使用依赖分层的方式构建镜像
- 在 buildkit 构建期间使用卷挂载
- 使用 maven 守护进程构建镜像
在每次运行之间,我们通过添加一个空行来更改源代码;在每个部分之间,我们删除所有构建的镜像,包括作为多阶段构建结果的中间镜像,这样是为了避免重复使用以前构建的镜像,以便得到每种方式更准确的构建时间。下面使用一个简单的 spring boot 项目进行测试。
二. 常规多阶段构建镜像
这是相关的dockerfile:
from openjdk:11-slim-buster as build copy .mvn .mvn copy mvnw . copy pom.xml . copy src src run ./mvnw -b package from openjdk:11-jre-slim-buster copy --from=build target/fast-maven-builds-1.0.jar . expose 8080 entrypoint ["java", "-jar", "fast-maven-builds-1.0.jar"]
让我们执行构建:
time docker_buildkit=0 docker build -t fast-maven:1.0 .
暂时忘记环境变量,我将在下一节中解释
以下是五次运行的结果:
* 0.36s user 0.53s system 0% cpu 1:53.06 total
* 0.36s user 0.56s system 0% cpu 1:52.50 total
* 0.35s user 0.55s system 0% cpu 1:56.92 total
* 0.36s user 0.56s system 0% cpu 2:04.55 total
* 0.38s user 0.61s system 0% cpu 2:04.68 total
三. 使用 buildkit 构建镜像
前面的命令行使用了docker_buildkit环境变量,这是告诉 docker 使用旧引擎的方式。如果你有一段时间没有更新 docker,那是你正在使用的引擎。如今,buildkit已取代它,成为新的默认设置。
buildkit 带来了多项性能改进:
- 自动垃圾收集
- 并发依赖解析
- 高效的指令缓存
- 构建缓存导入/导出
- 等等。
让我们在新引擎上重新执行之前的命令:
time docker build -t fast-maven:1.1 .
这是第一次运行的控制台日志的摘录:
…
=> => transferring context: 4.35kb
=> [build 2/6] copy .mvn .mvn
=> [build 3/6] copy mvnw .
=> [build 4/6] copy pom.xml .
=> [build 5/6] copy src src
=> [build 6/6] run ./mvnw -b package
…0.68s user 1.04s system 1% cpu 2:06.33 total
相同命令的以下执行具有稍微不同的输出:
…
=> => transferring context: 1.82kb
=> cached [build 2/6] copy .mvn .mvn
=> cached [build 3/6] copy mvnw .
=> cached [build 4/6] copy pom.xml .
=> [build 5/6] copy src src
=> [build 6/6] run ./mvnw -b package
…
请记住,我们在两次运行之间更改了源代码。我们不会更改的文件,即.mvn,mvnw和pom.xml,由 buildkit 缓存。但是这些资源很小,因此缓存不会显着改善构建时间。
* 0.69s user 1.01s system 1% cpu 2:05.08 total
* 0.65s user 0.95s system 1% cpu 1:58.51 total
* 0.68s user 0.99s system 1% cpu 1:59.31 total
* 0.64s user 0.95s system 1% cpu 1:59.82 total
快速浏览日志发现构建中的最大瓶颈是所有依赖项(包括插件)的下载。每次我们更改源代码时都会发生这种情况,这就是 buildkit 没有提高性能的原因。
四. 使用依赖分层的方式构建镜像
我们应该将精力集中在依赖关系上。为此,我们可以利用层并将构建分为两个步骤:
- 第一步,我们下载依赖
- 在第二个,我们做适当的包装
每一步都会创建一个层,第二个取决于第一个。
通过分层,如果我们在第二层更改源代码,则第一层不受影响,可以重复使用。我们不需要再次下载依赖项。新的dockerfile看起来像:
from openjdk:11-slim-buster as build copy .mvn .mvn copy mvnw . copy pom.xml . run ./mvnw -b dependency:go-offline copy src src run ./mvnw -b package from openjdk:11-jre-slim-buster copy --from=build target/fast-maven-builds-1.2.jar . expose 8080 entrypoint ["java", "-jar", "fast-maven-builds-1.2.jar"]
注意:go-offline不会下载所有内容。如果您尝试使用该-o选项(用于离线),该命令将不会成功运行。这是一个众所周知的老错误。在所有情况下,它都“足够好”。
让我们运行构建:
time docker build -t fast-maven:1.2 .
第一次运行比常规构建花费更多的时间:
0.84s user 1.21s system 1% cpu 2:35.47 total
但是,后续构建要快得多。更改源代码仅影响第二层,不会触发(大多数)依赖项的下载:
* 0.23s user 0.36s system 5% cpu 9.913 total
* 0.21s user 0.33s system 5% cpu 9.923 total
* 0.22s user 0.38s system 6% cpu 9.990 total
* 0.21s user 0.34s system 5% cpu 9.814 total
* 0.22s user 0.37s system 5% cpu 10.454 total
五. 在 buildkit 构建期间使用卷挂载
分层构建大大缩短了构建时间,不过还有一个问题,更改单个依赖项会使镜像依赖的层无效,因此我们需要再次下载所有依赖项。
幸运的是,buildkit在构建期间(而不仅仅是在运行期间)引入了卷挂载。有多种类型的挂载可用,但我们感兴趣的一种是缓存挂载。这是一项实验性功能,因此您需要明确选择加入:
dockerfile看起来像:
# syntax=docker/dockerfile:experimental from openjdk:11-slim-buster as build copy .mvn .mvn copy mvnw . copy pom.xml . copy src src # 使用缓存构建 run --mount=type=cache,target=/root/.m2,rw ./mvnw -b package from openjdk:11-jre-slim-buster copy --from=build target/fast-maven-builds-1.3.jar . expose 8080 entrypoint ["java", "-jar", "fast-maven-builds-1.3.jar"]
其中 # syntax=docker/dockerfile:experimental 用来开启实验性功能。
使用如下命令构建镜像:
time docker build -t fast-maven:1.3 .
构建时间高于常规构建,但仍低于分层构建:
0.71s user 1.01s system 1% cpu 1:50.50 total
以下构建与层相当:
* 0.22s user 0.33s system 5% cpu 9.677 total
* 0.30s user 0.36s system 6% cpu 10.603 total
* 0.24s user 0.37s system 5% cpu 10.461 total
* 0.24s user 0.39s system 6% cpu 10.178 total
* 0.24s user 0.35s system 5% cpu 10.283 total
六. 使用 maven 守护进程构建镜像
使用 maven 守护进程构建镜像的 dockerfile 文件内容如下:
from openjdk:11-slim-buster as build # 下载最新版本的 maven 守护进程 add https://github.com/mvndaemon/mvnd/releases/download/0.6.0/mvnd-0.6.0-linux-amd64.zip . # 更新包索引 run apt-get update \ # 安装 unzip && apt-get install unzip \ # 创建专用文件夹 && mkdir /opt/mvnd \ # 提取我们在前面下载的 mvnd && unzip mvnd-0.6.0-linux-amd64.zip \ # 将提取的存档内容移动到之前创建的文件夹 && mv mvnd-0.6.0-linux-amd64/* /opt/mvnd copy .mvn .mvn copy mvnw . copy pom.xml . copy src src # 使用 mvnd 代替 maven 包装器 run /opt/mvnd/bin/mvnd -b package from openjdk:11-jre-slim-buster copy --from=build target/fast-maven-builds-1.4.jar . expose 8080 entrypoint ["java", "-jar", "fast-maven-builds-1.4.jar"]
使用下面的命令构建镜像:
time docker build -t fast-maven:1.4 .
日志输出如下:
* 0.70s user 1.01s system 1% cpu 1:51.96 total
* 0.72s user 0.98s system 1% cpu 1:47.93 total
* 0.66s user 0.93s system 1% cpu 1:46.07 total
* 0.76s user 1.04s system 1% cpu 1:50.35 total
* 0.80s user 1.18s system 1% cpu 2:01.45 total
与常规构建镜像相比没有显着改善。
七. 结论
以下是所有执行时间的汇总:
基线 | 构建工具包 | 图层 | 卷挂载 | mvnd | |
---|---|---|---|---|---|
#1 (s) | 113.06 | 125.08 | 155.47 | 110.5 | 111.96 |
#2 (s) | 112.5 | 118.51 | 9.91 | 9.68 | 107.93 |
#3 (s) | 116.92 | 119.31 | 9.92 | 10.6 | 106.07 |
#4 (s) | 124.55 | 119.82 | 9.99 | 10.46 | 110.35 |
#5 (s) | 124.68 | 9.81 | 10.18 | 121.45 | |
#6 (s) | 10.45 | 10.28 | |||
#7 (s) | 44.71 | ||||
平均(秒) | 118.34 | 120.68 | 9.91 | 10.24 | 111.55 |
偏差 | 28.55 | 6.67 | 0.01 | 0.10 | 111.47 |
基线增益 (s) | 0 | -2.34 | 108.43 | 108.10 | 6.79 |
% 获得 | 0.00% | -1.98% | 91.63% | 91.35% | 5.74% |
在 docker 中加快 maven 构建的性能与常规构建有很大不同,限制因素是依赖项的下载速度,需要使用层来缓存依赖项。
对于 buildkit,建议使用新的缓存挂载功能,以避免在层失效时下载所有依赖项。
参考文章
https://blog.frankel.ch/faster-maven-builds/2/
到此这篇关于在docker中更快地构建maven项目的文章就介绍到这了,更多相关docker构建maven项目内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!