分享

在Docker中更快地构建Maven项目

 新用户3488XG6a 2021-11-22
目录

· . 概述

· . 常规多阶段构建镜像

· . 使用 Buildkit 构建镜像

· . 使用依赖分层的方式构建镜像

· . 在 Buildkit 构建期间使用卷挂载

· . 使用 Maven 守护进程构建镜像

· . 结论

· 参考文章

. 概述

本文将通过如下几个方式来构建 docker 镜像,通过记录每种方式的构建时间,从而得到在 Docker 中构建 Maven 项目最快的方式:

· 常规多阶段构建镜像

· 使用 Buildkit 构建镜像

· 使用依赖分层的方式构建镜像

·  Buildkit 构建期间使用卷挂载

· 使用 Maven 守护进程构建镜像

在每次运行之间,我们通过添加一个空行来更改源代码;在每个部分之间,我们删除所有构建的镜像,包括作为多阶段构建结果的中间镜像,这样是为了避免重复使用以前构建的镜像,以便得到每种方式更准确的构建时间。下面使用一个简单的 spring boot 项目进行测试。

. 常规多阶段构建镜像

这是相关的Dockerfile:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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

让我们执行构建:

1

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 带来了多项性能改进:

· 自动垃圾收集

· 并发依赖解析

· 高效的指令缓存

· 构建缓存导入/导出

· 等等。

让我们在新引擎上重新执行之前的命令:

1

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看起来像:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

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选项(用于离线),该命令将不会成功运行。这是一个众所周知的老错误。在所有情况下,它都“足够好”。

让我们运行构建:

1

time docker build -t fast-maven:1.2 .

第一次运行比常规构建花费更多的时间:

1

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看起来像:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

# 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 用来开启实验性功能。
使用如下命令构建镜像:

1

time docker build -t fast-maven:1.3 .

构建时间高于常规构建,但仍低于分层构建:

1

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 文件内容如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

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

使用下面的命令构建镜像:

1

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 构建的性能与常规构建有很大不同,限制因素是依赖项的下载速度,需要使用层来缓存依赖项。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多