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

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

推薦する

vue-cropper コンポーネントは画像の切り取りとアップロードを実現します

この記事では、画像の切り取りとアップロードを実装するためのvue-cropperコンポーネントの具体...

CD コマンドを使わずに Linux でディレクトリ/フォルダに入る方法

ご存知のとおり、cd コマンドがないと、Linux でディレクトリを切り替えることはできません。それ...

MySQLテーブルの内容の変更を監視し、MySQL binlogを有効にする

序文binlog は、MySQL のすべての追加、削除、および変更ステートメントを記録するバイナリ ...

Ubuntu 20.04 をインストールした後に行うべきこと (初心者向けガイド)

Ubuntu 20.04 がリリースされ、多くの新機能が導入されましたが、慣れていない機能も多くあ...

突然外部ネットワークからDockerにアクセスできなくなる問題の解決方法

マスターのメソッドによると、原因は sysctl net.ipv4.ip_forward であること...

ウェブデザインでよくある間違いのまとめ

Web ページを設計する過程で、デザイナーが間違いを犯すのは必然です。特に新人は、新しいアイデアを実...

VueのRender関数

目次1. ノード、ツリー、仮想DOM 2. 仮想DOM 2.1 データオブジェクトの詳細2.2 制約...

バックエンドの権限に基づいてナビゲーション メニューを動的に生成する Vue-router のサンプル コード

目次js の1. グローバルガードを登録する2. Vuex 状態管理グローバルキャッシュルート3. ...

JavaScript における var と let の違い

目次1. スコープはさまざまな方法で表現されます2. 変動昇進と非昇進の違い3. 一時的なデッドゾー...

Raspberry Pi msmtp と mutt のインストールと設定のチュートリアル

1. muttをインストールするsudo apt-get install mutt 2. msmtp...

Reactの親コンポーネントと子コンポーネント間のデータ転送の詳細な説明

目次1. 親コンポーネントが子コンポーネントにデータを渡す1.1. 親コンポーネントコード1.2. ...

VMware 仮想マシンで HTTP サービスを確立して分析する手順

1. xshell を使用して仮想マシンに接続するか、仮想マシンに直接コマンドを入力します。以下はx...

MYSQL の 10 の典型的な最適化ケースとシナリオ

目次1. SQL最適化の一般的な手順1. SQL実行計画の分析を説明する2. プロフィール分析を表示...

portainer を使用してリモート docker に接続するチュートリアル

Portainer は、Docker ホストと Docker Swarm クラスターの管理に使用でき...

スライダー間隔コンポーネントのネイティブ js 実装

この記事の例では、スライダー間隔コンポーネントを実装するためのjsの具体的なコードを参考までに共有し...