Docker で Maven プロジェクトをより速くビルドする

Docker で Maven プロジェクトをより速くビルドする

I. 概要

この記事では、次の方法で Docker イメージをビルドし、各方法のビルド時間を記録して、Docker で Maven プロジェクトをビルドする最も速い方法を紹介します。

  • 従来の多段階イメージ構築
  • Buildkit でイメージをビルドする
  • 階層化された依存関係を使用してイメージを構築する
  • Buildkit ビルド中にボリュームマウントを使用する
  • Mavenデーモンを使用してイメージを構築する

各実行の間に、空白行を追加してソース コードを変更します。各部分の間では、以前にビルドされたイメージの再利用を避け、各メソッドのビルド時間をより正確にするために、マルチステージ ビルドの結果としての中間イメージを含むすべてのビルドされたイメージを削除します。以下はテスト用のシンプルな Spring Boot プロジェクトです。

2. 従来の多段階イメージ構築

関連する Dockerfile は次のとおりです。

openjdk:11-slim-buster からビルド                         

コピー .mvn .mvn                                               
mvnw をコピーします。                                                  
pom.xml をコピーします。                                               
コピー src src                                                 

実行 ./mvnw -B パッケージ                                        

openjdk:11-jre-slim-buster より                              

--from=build target/fast-maven-builds-1.0.jar をコピーします。         

エクスポーズ8080

エントリポイント ["java", "-jar", "fast-maven-builds-1.0.jar"]

ビルドを実行してみましょう:

時間 DOCKER_BUILDKIT=0 docker build -t fast-maven:1.0 。      

環境変数については今は忘れてください。次のセクションで説明します。

5 回の実行の結果は次のとおりです。

* 0.36秒 ユーザー 0.53秒 システム 0% CPU 1:53.06 合計
* ユーザー 0.36 秒、システム 0.56 秒、CPU 0%、合計 1:52.50
* ユーザー 0.35 秒、システム 0.55 秒、CPU 0%、合計 1:56.92
* ユーザー 0.36 秒、システム 0.56 秒、CPU 0%、合計 2:04.55
* ユーザー 0.38 秒、システム 0.61 秒、CPU 0%、合計 2:04.68

3. Buildkitを使用してイメージをビルドする

前のコマンドラインでは DOCKER_BUILDKIT 環境変数が使用されており、これは Docker に古いエンジンを使用するように指示する方法です。しばらく Docker を更新していない場合は、それが使用しているエンジンです。現在、BuildKit が新しいデフォルトとして置き換えられました。

BuildKit により、パフォーマンスがいくつか向上します。

  • 自動ガベージコレクション
  • 同時依存関係の解決
  • 効率的な命令キャッシュ
  • ビルドキャッシュのインポート/エクスポート

新しいエンジンで前のコマンドを再実行してみましょう。

docker build -t fast-maven:1.1 を実行します。

以下は、最初の実行時のコンソール ログからの抜粋です。

...
=> => コンテキストを転送中: 4.35kB
=> [ビルド 2/6] .mvn .mvn をコピー
=> [ビルド 3/6] mvnw をコピーします。
=> [ビルド 4/6] pom.xml をコピーします。
=> [ビルド 5/6] コピー src src
=> [ビルド 6/6] ./mvnw -B package を実行
...

0.68秒 ユーザー 1.04秒 システム 1% CPU 2:06.33 合計

同じコマンドを次のように実行すると、出力が若干異なります。

...
=> =>コンテキストを転送中: 1.82kB
=> キャッシュ済み [ビルド 2/6] コピー .mvn .mvn
=> キャッシュ済み [ビルド 3/6] mvnw をコピーします。
=> キャッシュ済み [ビルド 4/6] pom.xml をコピーします。
=> [ビルド 5/6] コピー src src
=> [ビルド 6/6] ./mvnw -B package を実行
...

実行間でソース コードが変更されたことに留意してください。変更しないファイル、つまり .mvn、mvnw、pom.xml は BuildKit によってキャッシュされます。しかし、これらのリソースは小さいため、キャッシュしてもビルド時間が大幅に改善されることはありません。

* ユーザー 0.69 秒、システム 1.01 秒、CPU 1%、合計 2:05.08
* ユーザー 0.65 秒、システム 0.95 秒、CPU 1%、合計 1:58.51
* 0.68秒 ユーザー 0.99秒 システム 1% CPU 1:59.31 合計
* ユーザー 0.64 秒、システム 0.95 秒、CPU 1%、合計 1:59.82

ログをざっと見てみると、ビルドにおける最大のボトルネックは、すべての依存関係 (プラグインを含む) のダウンロードであることがわかりました。これはソース コードを変更するたびに発生するため、BuildKit ではパフォーマンスが向上しません。

4. 依存関係の階層化を使用してイメージを構築する

依存関係に焦点を当てる必要があります。これを実現するには、レイヤーを利用してビルドを 2 つのステップに分割します。

  • 最初のステップは依存関係をダウンロードすることです
  • 2つ目は適切な梱包をすることです

各ステップでレイヤーが作成され、2 番目のステップは最初のステップに依存します。
階層化により、2 番目のレイヤーのソース コードを変更しても、1 番目のレイヤーは影響を受けず、再利用できます。依存関係を再度ダウンロードする必要はありません。新しい Dockerfile は次のようになります。

openjdk:11-slim-buster からビルド

コピー .mvn .mvn
mvnw をコピーします。
pom.xml をコピーします。

実行 ./mvnw -B dependency:go-offline                          

コピー src src

実行 ./mvnw -B パッケージ                                        

openjdk:11-jre-slim-buster より

--from=build target/fast-maven-builds-1.2.jar をコピーします。

エクスポーズ8080

エントリポイント ["java", "-jar", "fast-maven-builds-1.2.jar"]

注意: オフラインではすべてがダウンロードされるわけではありません。 -o オプション (オフライン用) を使用すると、コマンドは正常に実行されません。これはよく知られている古い間違いです。いずれの場合も、「十分」です。

ビルドを実行してみましょう:

docker build -t fast-maven:1.2 を実行します。

最初の実行は通常のビルドよりもはるかに時間がかかります。

0.84秒 ユーザー 1.21秒 システム 1% CPU 2:35.47 合計

ただし、その後のビルドははるかに高速になります。ソース コードを変更すると、第 2 レイヤーにのみ影響し、(ほとんどの) 依存関係のダウンロードはトリガーされません。

* 0.23秒 ユーザー 0.36秒 システム 5% CPU 9.913 合計
* ユーザー 0.21 秒、システム 0.33 秒、CPU 5%、合計 9.923
* 0.22秒 ユーザー 0.38秒 システム 6% CPU 9.990 合計
* ユーザー 0.21 秒、システム 0.34 秒、CPU 5%、合計 9.814
* 0.22秒 ユーザー 0.37秒 システム 5% CPU 10.454 合計

5. Buildkit ビルド中にボリュームマウントを使用する

レイヤードビルドによりビルド時間が大幅に短縮されますが、それでも問題が残ります。単一の依存関係を変更すると、イメージが依存するレイヤーが無効になるため、すべての依存関係を再度ダウンロードする必要があります。

幸いなことに、BuildKit ではビルド時(実行時だけでなく)にボリュームのマウントが導入されています。利用できるマウントにはいくつかの種類がありますが、ここで注目するのはキャッシュ マウントです。これは実験的な機能なので、明示的にオプトインする必要があります。

Dockerfile は次のようになります。

# 構文=docker/dockerfile:実験的                      
openjdk:11-slim-buster からビルド

コピー .mvn .mvn
mvnw をコピーします。
pom.xml をコピーします。
コピー src src

# キャッシュを使用してビルドする RUN --mount=type=cache,target=/root/.m2,rw ./mvnw -B package 

openjdk:11-jre-slim-buster より

--from=build target/fast-maven-builds-1.3.jar をコピーします。

エクスポーズ8080

エントリポイント ["java", "-jar", "fast-maven-builds-1.3.jar"]

# syntax=docker/dockerfile:experimental は、実験的な機能を有効にするために使用されます。
イメージをビルドするには、次のコマンドを使用します。

時間 docker build -t fast-maven:1.3 。

ビルド時間は通常のビルドよりも長くなりますが、レイヤード ビルドよりも短くなります。

0.71秒 ユーザー 1.01秒 システム 1% CPU 1:50.50 合計

次の構成要素はレイヤーと同等です。

* 0.22秒 ユーザー 0.33秒 システム 5% CPU 9.677 合計
* 0.30秒 ユーザー 0.36秒 システム 6% CPU 10.603 合計
* 0.24秒 ユーザー 0.37秒 システム 5% CPU 10.461 合計
* ユーザー 0.24 秒、システム 0.39 秒、CPU 6%、合計 10.178
* ユーザー 0.24 秒、システム 0.35 秒、CPU 5%、合計 10.283

6. Mavenデーモンを使用してイメージをビルドする

Maven デーモンを使用してイメージを構築するための Dockerfile ファイルの内容は次のとおりです。

openjdk:11-slim-buster からビルド
# Maven デーモンの最新バージョンをダウンロードします。https://github.com/mvndaemon/mvnd/releases/download/0.6.0/mvnd-0.6.0-linux-amd64.zip 。 
# パッケージインデックスを更新する RUN apt-get update \     
# 解凍してインストール
 && apt-get install unzip \     
# 専用フォルダを作成 && mkdir /opt/mvnd \       
# 先ほどダウンロードしたmvndファイルを抽出します
 && mvnd-0.6.0-linux-amd64.zip を解凍します \ 
# 抽出したアーカイブの内容を先ほど作成したフォルダに移動します && mv mvnd-0.6.0-linux-amd64/* /opt/mvnd                    

コピー .mvn .mvn
mvnw をコピーします。
pom.xml をコピーします。
コピー src src
# Mavenラッパーの代わりにmvndを使用する RUN /opt/mvnd/bin/mvnd -B package                            

openjdk:11-jre-slim-buster より

--from=build target/fast-maven-builds-1.4.jar をコピーします。

エクスポーズ8080

エントリポイント ["java", "-jar", "fast-maven-builds-1.4.jar"]

次のコマンドを使用してイメージをビルドします。

時間 docker build -t fast-maven:1.4 。

ログ出力は次のようになります。

* 0.70秒 ユーザー 1.01秒 システム 1% CPU 1:51.96 合計
* 0.72秒 ユーザー 0.98秒 システム 1% CPU 1:47.93 合計
* 0.66秒 ユーザー 0.93秒 システム 1% CPU 1:46.07 合計
* ユーザー 0.76 秒、システム 1.04 秒、CPU 1%、合計 1:50.35
* ユーザー 0.80 秒、システム 1.18 秒、CPU 1%、合計 2:01.45

通常のビルド イメージと比べて大きな改善はありません。

VII. 結論

すべての実行時間の概要は次のとおりです。

ベースラインビルドツールキットレイヤーボリュームマウントMVND
#1 (ス) 113.06 125.08 155.47 110.5 111.96
#2 (ス) 112.5 118.51 9.91 9.68 107.93
#3 (ス) 116.92 119.31 9.92 10.6 106.07
#4 (ス) 124.55 119.82 9.99 10.46 110.35
#5 (ス) 124.68 9.81 10.18 121.45
#6 (ス) 10.45 10.28
#7 (ス) 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 プロジェクトの構築の詳細については、123WORDPRESS.COM の以前の記事を検索するか、次の関連記事を引き続き参照してください。今後も 123WORDPRESS.COM を応援していただければ幸いです。

以下もご興味があるかもしれません:
  • Dockerはjenkins+mavenコード構築および展開プラットフォームを構築します
  • DockerイメージをビルドするためのMavenプラグインの実装手順
  • Maven+Tomcat 基本イメージを構築する Docker の実装
  • Maven プラグインを使用して Docker でイメージをビルドする方法
  • Mavenプラグインを使用してDockerイメージを構築する方法についての簡単な説明

<<:  MySQL データベースのバックアップをスケジュールするいくつかの方法 (包括的)

>>:  今日、私は非常に奇妙なクリックの問題に遭遇し、自分で解決しました

推薦する

JavaScript にはすでに Object があるのに、なぜ Map が必要なのでしょうか?

目次1. オブジェクトをマップとして扱わない1. 未定義のプロパティはプロトタイプチェーンを通じてア...

さまざまなブラウザに対応するためにCSSで指定フォント@font-faceを導入する際の問題

Web ページを作成するときに、特定のフォントを使用したい場合は、 @font-faceを介して参照...

4つのReactコンポーネントにおけるDOMスタイル設定の詳細な説明

1. インラインスタイル仮想DOMにインラインスタイルを追加するには、式を使用してスタイルオブジェク...

Nginx フォワード プロキシとリバース プロキシ、および負荷分散機能の構成コード例

この記事は主に、Nginx のフォワード プロキシとリバース プロキシ、および負荷分散機能の設定コー...

MySQL ストアド プロシージャと共通関数のコード分析

mysql ストアド プロシージャの概念:特定のタスク (クエリと更新) を実行できる、データベース...

vue+iviewのメニューとタブの連携方法

Vue+iview メニューとタブのリンク現在、vue+iview を使用してバックエンド管理システ...

Nginxはドメイン名のアクセス方法を定義しています

最近Nginxを構築しているのですが、ドメイン名でアクセスできません。 nginx 構成ファイル n...

MySQL データベースの最適化: テーブルとデータベースのシャーディング操作の詳細な説明

この記事では、例を使用して、MySQL データベースの最適化のためのテーブルおよびデータベース シャ...

Python 仮想環境のインストールとアンインストールの方法と発生する問題

Ubuntu16.04 のインストールとアンインストール pip実験環境Ubuntu 16.04; ...

ウェブページで任意のフォントを使用する実践的な操作とデモ

以前、「Web ページにシステムに組み込まれていないフォントを埋め込む」という研究をしたことがありま...

写真をアップロードして顔を認識する Vue+axios サンプルコード

目次Axios リクエストQs処理データ分析Vantアップロードファイル形式完全なコードこの記事では...

HTML webpackプラグインの使用に関する簡単な分析

html-webpack-pluginプラグインを使用してページを開始すると、htmlページをメモリ...

CSS3 で作成したホバーズーム効果

結果:実装コード: html <link href='https://fonts.go...

Vue の要素カレンダー コンポーネントを使用したサンプル コード

まず効果図を見てみましょう: 完全なコードは添付されています <テンプレート> <...

Docker を使ってゼロから SOLO 個人ブログを構築する方法

目次1. 環境整備2. Dockerをインストールする3. MySQLマスタースレーブデータベースを...