在Docker中更快地構(gòu)建Maven項目
一. 概述
本文將通過如下幾個方式來構(gòu)建 docker 鏡像,通過記錄每種方式的構(gòu)建時間,從而得到在 Docker 中構(gòu)建 Maven 項目最快的方式:
- 常規(guī)多階段構(gòu)建鏡像
- 使用 Buildkit 構(gòu)建鏡像
- 使用依賴分層的方式構(gòu)建鏡像
- 在 Buildkit 構(gòu)建期間使用卷掛載
- 使用 Maven 守護進程構(gòu)建鏡像
在每次運行之間,我們通過添加一個空行來更改源代碼;在每個部分之間,我們刪除所有構(gòu)建的鏡像,包括作為多階段構(gòu)建結(jié)果的中間鏡像,這樣是為了避免重復使用以前構(gòu)建的鏡像,以便得到每種方式更準確的構(gòu)建時間。下面使用一個簡單的 spring boot 項目進行測試。
二. 常規(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 .
暫時忘記環(huán)境變量,我將在下一節(jié)中解釋
以下是五次運行的結(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 使用舊引擎的方式。如果你有一段時間沒有更新 Docker,那是你正在使用的引擎。如今,BuildKit已取代它,成為新的默認設置。
BuildKit 帶來了多項性能改進:
- 自動垃圾收集
- 并發(fā)依賴解析
- 高效的指令緩存
- 構(gòu)建緩存導入/導出
- 等等。
讓我們在新引擎上重新執(zhí)行之前的命令:
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
相同命令的以下執(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
...
請記住,我們在兩次運行之間更改了源代碼。我們不會更改的文件,即.mvn,mvnw和pom.xml,由 BuildKit 緩存。但是這些資源很小,因此緩存不會顯著改善構(gòu)建時間。
* 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)建中的最大瓶頸是所有依賴項(包括插件)的下載。每次我們更改源代碼時都會發(fā)生這種情況,這就是 BuildKit 沒有提高性能的原因。
四. 使用依賴分層的方式構(gòu)建鏡像
我們應該將精力集中在依賴關(guān)系上。為此,我們可以利用層并將構(gòu)建分為兩個步驟:
- 第一步,我們下載依賴
- 在第二個,我們做適當?shù)陌b
每一步都會創(chuàng)建一個層,第二個取決于第一個。
通過分層,如果我們在第二層更改源代碼,則第一層不受影響,可以重復使用。我們不需要再次下載依賴項。新的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不會下載所有內(nèi)容。如果您嘗試使用該-o選項(用于離線),該命令將不會成功運行。這是一個眾所周知的老錯誤。在所有情況下,它都“足夠好”。
讓我們運行構(gòu)建:
time docker build -t fast-maven:1.2 .
第一次運行比常規(guī)構(gòu)建花費更多的時間:
0.84s user 1.21s system 1% cpu 2:35.47 total
但是,后續(xù)構(gòu)建要快得多。更改源代碼僅影響第二層,不會觸發(fā)(大多數(shù))依賴項的下載:
* 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)建時間,不過還有一個問題,更改單個依賴項會使鏡像依賴的層無效,因此我們需要再次下載所有依賴項。
幸運的是,BuildKit在構(gòu)建期間(而不僅僅是在運行期間)引入了卷掛載。有多種類型的掛載可用,但我們感興趣的一種是緩存掛載。這是一項實驗性功能,因此您需要明確選擇加入:
Dockerfile看起來像:
# 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 用來開啟實驗性功能。
使用如下命令構(gòu)建鏡像:
time docker build -t fast-maven:1.3 .
構(gòu)建時間高于常規(guī)構(gòu)建,但仍低于分層構(gòu)建:
0.71s user 1.01s system 1% cpu 1:50.50 total
以下構(gòu)建與層相當:
* 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 守護進程構(gòu)建鏡像
使用 Maven 守護進程構(gòu)建鏡像的 Dockerfile 文件內(nèi)容如下:
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 \ # 創(chuàng)建專用文件夾 && mkdir /opt/mvnd \ # 提取我們在前面下載的 mvnd && unzip mvnd-0.6.0-linux-amd64.zip \ # 將提取的存檔內(nèi)容移動到之前創(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)建鏡像相比沒有顯著改善。
七. 結(jié)論
以下是所有執(zhí)行時間的匯總:
| 基線 | 構(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)建有很大不同,限制因素是依賴項的下載速度,需要使用層來緩存依賴項。
對于 BuildKit,建議使用新的緩存掛載功能,以避免在層失效時下載所有依賴項。
參考文章
https://blog.frankel.ch/faster-maven-builds/2/
到此這篇關(guān)于在Docker中更快地構(gòu)建Maven項目的文章就介紹到這了,更多相關(guān)Docker構(gòu)建Maven項目內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
docker logs-查看docker容器日志的實現(xiàn)
這篇文章主要介紹了docker logs-查看docker容器日志的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-03-03
低版本Docker升級高版本Docker的詳細教程及成功避坑
如果我們使用docker來管理容器,那么保持docker引擎的更新將會是十分重要的,下面這篇文章主要給大家介紹了關(guān)于低版本Docker升級高版本Docker的詳細教程及成功避坑,文中通過圖文介紹的非常詳細,需要的朋友可以參考下2023-05-05
Docker搭建prometheus(普羅米修斯)的方法步驟
phometheus:當前一套非常流行的開源監(jiān)控和報警系統(tǒng),本文主要介紹了Docker搭建prometheus(普羅米修斯)的方法步驟,具有一定的參考價值,感興趣的可以了解一下2024-02-02
在Ubuntu 16.04上用Docker Swarm和DigitalOcean創(chuàng)建一個Docker容器集群的方法
這篇文章主要介紹了在Ubuntu 16.04上用Docker Swarm和DigitalOcean創(chuàng)建一個Docker容器集群的方法,需要的的朋友參考下吧2017-01-01

