在Docker中更快地構(gòu)建Maven項(xiàng)目
一. 概述
本文將通過(guò)如下幾個(gè)方式來(lái)構(gòu)建 docker 鏡像,通過(guò)記錄每種方式的構(gòu)建時(shí)間,從而得到在 Docker 中構(gòu)建 Maven 項(xiàng)目最快的方式:
- 常規(guī)多階段構(gòu)建鏡像
- 使用 Buildkit 構(gòu)建鏡像
- 使用依賴分層的方式構(gòu)建鏡像
- 在 Buildkit 構(gòu)建期間使用卷掛載
- 使用 Maven 守護(hù)進(jìn)程構(gòu)建鏡像
在每次運(yùn)行之間,我們通過(guò)添加一個(gè)空行來(lái)更改源代碼;在每個(gè)部分之間,我們刪除所有構(gòu)建的鏡像,包括作為多階段構(gòu)建結(jié)果的中間鏡像,這樣是為了避免重復(fù)使用以前構(gòu)建的鏡像,以便得到每種方式更準(zhǔn)確的構(gòu)建時(shí)間。下面使用一個(gè)簡(jiǎn)單的 spring boot 項(xiàng)目進(jìn)行測(cè)試。
二. 常規(guī)多階段構(gòu)建鏡像
這是相關(guān)的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"]
讓我們執(zhí)行構(gòu)建:
time DOCKER_BUILDKIT=0 docker build -t fast-maven:1.0 .
暫時(shí)忘記環(huán)境變量,我將在下一節(jié)中解釋
以下是五次運(yùn)行的結(jié)果:
* 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 構(gòu)建鏡像
前面的命令行使用了DOCKER_BUILDKIT環(huán)境變量,這是告訴 Docker 使用舊引擎的方式。如果你有一段時(shí)間沒(méi)有更新 Docker,那是你正在使用的引擎。如今,BuildKit已取代它,成為新的默認(rèn)設(shè)置。
BuildKit 帶來(lái)了多項(xiàng)性能改進(jìn):
- 自動(dòng)垃圾收集
- 并發(fā)依賴解析
- 高效的指令緩存
- 構(gòu)建緩存導(dǎo)入/導(dǎo)出
- 等等。
讓我們?cè)谛乱嫔现匦聢?zhí)行之前的命令:
time docker build -t fast-maven:1.1 .
這是第一次運(yùn)行的控制臺(tái)日志的摘錄:
...
=> => 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
相同命令的以下執(zhí)行具有稍微不同的輸出:
...
=> => 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
...
請(qǐng)記住,我們?cè)趦纱芜\(yùn)行之間更改了源代碼。我們不會(huì)更改的文件,即.mvn,mvnw和pom.xml,由 BuildKit 緩存。但是這些資源很小,因此緩存不會(huì)顯著改善構(gòu)建時(shí)間。
* 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
快速瀏覽日志發(fā)現(xiàn)構(gòu)建中的最大瓶頸是所有依賴項(xiàng)(包括插件)的下載。每次我們更改源代碼時(shí)都會(huì)發(fā)生這種情況,這就是 BuildKit 沒(méi)有提高性能的原因。
四. 使用依賴分層的方式構(gòu)建鏡像
我們應(yīng)該將精力集中在依賴關(guān)系上。為此,我們可以利用層并將構(gòu)建分為兩個(gè)步驟:
- 第一步,我們下載依賴
- 在第二個(gè),我們做適當(dāng)?shù)陌b
每一步都會(huì)創(chuàng)建一個(gè)層,第二個(gè)取決于第一個(gè)。
通過(guò)分層,如果我們?cè)诘诙痈脑创a,則第一層不受影響,可以重復(fù)使用。我們不需要再次下載依賴項(xiàng)。新的Dockerfile看起來(lái)像:
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不會(huì)下載所有內(nèi)容。如果您嘗試使用該-o選項(xiàng)(用于離線),該命令將不會(huì)成功運(yùn)行。這是一個(gè)眾所周知的老錯(cuò)誤。在所有情況下,它都“足夠好”。
讓我們運(yùn)行構(gòu)建:
time docker build -t fast-maven:1.2 .
第一次運(yùn)行比常規(guī)構(gòu)建花費(fèi)更多的時(shí)間:
0.84s user 1.21s system 1% cpu 2:35.47 total
但是,后續(xù)構(gòu)建要快得多。更改源代碼僅影響第二層,不會(huì)觸發(fā)(大多數(shù))依賴項(xiàng)的下載:
* 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 構(gòu)建期間使用卷掛載
分層構(gòu)建大大縮短了構(gòu)建時(shí)間,不過(guò)還有一個(gè)問(wèn)題,更改單個(gè)依賴項(xiàng)會(huì)使鏡像依賴的層無(wú)效,因此我們需要再次下載所有依賴項(xiàng)。
幸運(yùn)的是,BuildKit在構(gòu)建期間(而不僅僅是在運(yùn)行期間)引入了卷掛載。有多種類型的掛載可用,但我們感興趣的一種是緩存掛載。這是一項(xiàng)實(shí)驗(yàn)性功能,因此您需要明確選擇加入:
Dockerfile看起來(lái)像:
# syntax=docker/dockerfile:experimental FROM openjdk:11-slim-buster as build COPY .mvn .mvn COPY mvnw . COPY pom.xml . COPY src src # 使用緩存構(gòu)建 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 用來(lái)開啟實(shí)驗(yàn)性功能。
使用如下命令構(gòu)建鏡像:
time docker build -t fast-maven:1.3 .
構(gòu)建時(shí)間高于常規(guī)構(gòu)建,但仍低于分層構(gòu)建:
0.71s user 1.01s system 1% cpu 1:50.50 total
以下構(gòu)建與層相當(dāng):
* 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 守護(hù)進(jìn)程構(gòu)建鏡像
使用 Maven 守護(hù)進(jìn)程構(gòu)建鏡像的 Dockerfile 文件內(nèi)容如下:
FROM openjdk:11-slim-buster as build # 下載最新版本的 Maven 守護(hù)進(jìn)程 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 \ # 創(chuàng)建專用文件夾 && mkdir /opt/mvnd \ # 提取我們?cè)谇懊嫦螺d的 mvnd && unzip mvnd-0.6.0-linux-amd64.zip \ # 將提取的存檔內(nèi)容移動(dòng)到之前創(chuàng)建的文件夾 && 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"]
使用下面的命令構(gòu)建鏡像:
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
與常規(guī)構(gòu)建鏡像相比沒(méi)有顯著改善。
七. 結(jié)論
以下是所有執(zhí)行時(shí)間的匯總:
基線 | 構(gòu)建工具包 | 圖層 | 卷掛載 | MVND | |
---|---|---|---|---|---|
#1 (S) | 113.06 | 125.08 | 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) | |||||
平均(秒) | 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 構(gòu)建的性能與常規(guī)構(gòu)建有很大不同,限制因素是依賴項(xiàng)的下載速度,需要使用層來(lái)緩存依賴項(xiàng)。
對(duì)于 BuildKit,建議使用新的緩存掛載功能,以避免在層失效時(shí)下載所有依賴項(xiàng)。
參考文章
https://blog.frankel.ch/faster-maven-builds/2/
到此這篇關(guān)于在Docker中更快地構(gòu)建Maven項(xiàng)目的文章就介紹到這了,更多相關(guān)Docker構(gòu)建Maven項(xiàng)目?jī)?nèi)容請(qǐng)搜索本站以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持本站!
版權(quán)聲明:本站文章來(lái)源標(biāo)注為YINGSOO的內(nèi)容版權(quán)均為本站所有,歡迎引用、轉(zhuǎn)載,請(qǐng)保持原文完整并注明來(lái)源及原文鏈接。禁止復(fù)制或仿造本網(wǎng)站,禁止在非www.sddonglingsh.com所屬的服務(wù)器上建立鏡像,否則將依法追究法律責(zé)任。本站部分內(nèi)容來(lái)源于網(wǎng)友推薦、互聯(lián)網(wǎng)收集整理而來(lái),僅供學(xué)習(xí)參考,不代表本站立場(chǎng),如有內(nèi)容涉嫌侵權(quán),請(qǐng)聯(lián)系alex-e#qq.com處理。