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 データベースのバックアップをスケジュールするいくつかの方法 (包括的)

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

推薦する

MySQL 5.5.56 インストール不要版の設定方法

MySQL 5.5.56無料インストール版の設定方法をテキストコードで詳しく説明します。具体的な内容...

react-virtualized を使用して、動的な高さを持つ画像の長いリストを実装する

目次開発中に発生した問題解決具体的な実装実績まとめバーチャルリストは、スクロールコンテナ要素の表示領...

Centos7環境でMySQL 5.6のインスタンスを複数作成する方法の詳細な説明

この記事では、CentOS 7 環境で MySQL 5.6 の複数のインスタンスを作成する方法につい...

アプレットにおけるwx.getUserProfileインターフェースの具体的な使用

最近、WeChatミニプログラムは、監査ミニプログラムのwx.loginおよびwx.getUserI...

Linux での MySQL 5.7.18 yum のアンインストールからインストールまでのプロセスの図

いろいろ苦労しましたが、やっと yum インストールの手順がわかりました。以前、バイナリ パッケージ...

Nginx をベースに特定の IP への短期アクセス数を制限する

特定の期間内に特定の IP へのアクセス回数を制限する方法は、特に悪意のある DDOS 攻撃に直面し...

MySQL 8.0 WITH クエリの詳細

目次MySQL 8 の WITH クエリについて学ぶ1. 例3. 練習するMySQL 8 の WIT...

MySQL がデータの削除と挿入に非常に時間がかかる問題の解決策

会社の開発者がテスト環境で挿入ステートメントを実行すると、正常に実行されるまでに 10 秒以上かかり...

MySQLからOracleへのリアルタイム同期ソリューションの詳細な説明

1 要件の概要MySQL5.6本番データベースの複数のテーブルのデータは、Oracle11gデータウ...

JavaScript ファクトリーパターンの説明

目次シンプルファクトリーファクトリーメソッド安全な工場方法アブストラクトファクトリー要約するシンプル...

Linux でユーザー アカウントをロックおよびロック解除する 3 つの方法

組織内で何らかのパスワード ポリシーがすでに実装されている場合は、この記事を読む必要はありません。た...

...

MySQL 5.7 でパスワードを変更する簡単な方法

これは公式のスクリーンショットです。MySQL 5.7 をインストールすると、デフォルトのパスワード...