ドッカーを使用してMavenビルドを自動化しようとしています。ビルドするプロジェクトは、すべての依存関係をダウンロードするのに20分近くかかります。そのため、これらの依存関係をキャッシュするdockerイメージをビルドしようとしましたが、保存されないようです。私のDockerfileは
FROM maven:Alpine
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
ADD pom.xml /usr/src/app
RUN mvn dependency:go-offline
イメージがビルドされ、すべてがダウンロードされます。ただし、結果のイメージはベースmaven:Alpine
イメージと同じサイズであるため、イメージの依存関係がキャッシュされていないようです。イメージをmvn compile
に使用しようとすると、すべてを再ダウンロードするのに20分かかります。
ビルドを実行するためにイメージを使用するたびにダウンロードする必要がないように、依存関係をキャッシュするMavenイメージをビルドすることは可能ですか?
私は次のコマンドを実行しています:
docker build -t my-maven .
docker run -it --rm --name my-maven-project -v "$PWD":/usr/src/mymaven -w /usr/src/mymaven my-maven mvn compile
私の理解では、Dockerビルドプロセス中にRUN
が行うことはすべて、結果のイメージの一部になります。
通常、pom.xml
ファイルには変更はありませんが、Dockerイメージビルドを開始しようとするときに、他のソースコードがいくつか変更されるだけです。そのような状況では、これを行うことができます:
参考までに:
FROM maven:3-jdk-8
ENV HOME=/home/usr/app
RUN mkdir -p $HOME
WORKDIR $HOME
# 1. add pom.xml only here
ADD pom.xml $HOME
# 2. start downloading dependencies
RUN ["/usr/local/bin/mvn-entrypoint.sh", "mvn", "verify", "clean", "--fail-never"]
# 3. add all source code and start compiling
ADD . $HOME
RUN ["mvn", "package"]
EXPOSE 8005
CMD ["Java", "-jar", "./target/dist.jar"]
キーは次のとおりです。
pom.xml
ファイルを追加します。
それからmvn verify --fail-never
it、Maven依存関係をダウンロードします。
すべてのソースファイルを追加し、コンパイルを開始します(mvn package
)。
pom.xml
ファイルに変更がある場合、またはこのスクリプトを初めて実行する場合、dockerは1-> 2-> 3.を実行します。pom.xml
ファイルに変更がない場合、Dockerはステップ1、2をスキップして直接3を実行します。
この簡単なトリックは、他の多くのパッケージ管理環境(gradle、yarn、npm、pip)で使用できます。
編集:
他のコメントと回答が示唆するように、それに応じてmvn dependency:resolve
またはmvn dependency:go-offline
の使用も検討する必要があります。
ベースとして使用している画像には、定義する親画像があります
VOLUME "$USER_HOME_DIR/.m2"
その結果、ビルド中にすべてのファイルが$USER_HOME_DIR/.m2
に書き込まれますが、ボリュームであることが予想されるため、これらのファイルはいずれもコンテナーイメージに永続化されません。
現在、Dockerにはそのボリューム定義を登録解除する方法はないため、公式のMavenイメージを使用するのではなく、別のMavenイメージを作成する必要があります。
@Kimは最も近いですが、まだ完全ではありません。 --fail-never
の追加は正しいとは思わない、たとえそれが仕事を成し遂げたとしても。
verify
コマンドにより、多くのプラグインが実行されますが、これは問題です(私にとって)-依存関係をインストールするだけの場合は、実行する必要があるとは思いません!また、マルチモジュールビルドとjavascriptサブビルドがあるため、セットアップがさらに複雑になります。
ただし、次のコマンドでverify
を実行すると、使用するプラグインが増えるため、ダウンロードする依存関係が増えるため、install
のみを実行するだけでは不十分です。関連する読み取り: Maven:ビルドライフサイクルの概要
基本的に、各プラグインを無効にするプロパティを見つけて、それらを1つずつ追加する必要があります。これにより、ビルドが壊れないようになります。
WORKDIR /srv
# cache Maven dependencies
ADD cli/pom.xml /srv/cli/
ADD core/pom.xml /srv/core/
ADD parent/pom.xml /srv/parent/
ADD rest-api/pom.xml /srv/rest-api/
ADD web-admin/pom.xml /srv/web-admin/
ADD pom.xml /srv/
RUN mvn -B clean install -DskipTests -Dcheckstyle.skip -Dasciidoctor.skip -Djacoco.skip -Dmaven.gitcommitid.skip -Dspring-boot.repackage.skip -Dmaven.exec.skip=true -Dmaven.install.skip -Dmaven.resources.skip
# cache YARN dependencies
ADD ./web-admin/package.json ./web-admin/yarn.lock /srv/web-admin/
RUN yarn --non-interactive --frozen-lockfile --no-progress --cwd /srv/web-admin install
# build the project
ADD . /srv
RUN mvn -B clean install
しかし、いくつかのプラグインはそれほど簡単にスキップされません-私はmavenの専門家ではありません(したがって、cliオプションを無視する理由はわかりません-それはバグかもしれません)が、以下はorg.codehaus.mojo:exec-maven-plugin
に対して期待どおりに動作します
<project>
<properties>
<maven.exec.skip>false</maven.exec.skip>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.2</version>
<executions>
<execution>
<id>yarn install</id>
<goals>
<goal>exec</goal>
</goals>
<phase>initialize</phase>
<configuration>
<executable>yarn</executable>
<arguments>
<argument>install</argument>
</arguments>
<skip>${maven.exec.skip}</skip>
</configuration>
</execution>
<execution>
<id>yarn run build</id>
<goals>
<goal>exec</goal>
</goals>
<phase>compile</phase>
<configuration>
<executable>yarn</executable>
<arguments>
<argument>run</argument>
<argument>build</argument>
</arguments>
<skip>${maven.exec.skip}</skip>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
明示的な<skip>${maven.exec.skip}</skip>
に注意してください-他のプラグインはcliパラメーターからこれを選択しますが、このプラグインは選択しません(-Dmaven.exec.skip=true
も-Dexec.skip=true
も単独では機能しません)
お役に立てれば
@Kimの回答と似ていますが、dependency:resolve
mvnコマンドを使用します。これが私の完全なDockerfileです。
FROM maven:3.5.0-jdk-8-Alpine
WORKDIR /usr/src/app
# First copy only the pom file. This is the file with less change
COPY ./pom.xml .
# Download the package and make it cached in docker image
RUN mvn -B -f ./pom.xml -s /usr/share/maven/ref/settings-docker.xml dependency:resolve
# Copy the actual code
COPY ./ .
# Then build the code
RUN mvn -B -f ./pom.xml -s /usr/share/maven/ref/settings-docker.xml package
# The rest is same as usual
EXPOSE 8888
CMD ["Java", "-jar", "./target/YOUR-APP.jar"]
数日苦労した後、私はこの中間キャッシングを使用してこのキャッシュを実行しました。このトピックは非常に有用であり、Google検索のフロントページに頻繁に表示されるため、ここで調査結果を要約します。
#docker build -t dependencies .
From ubuntu
COPY pom.xml pom.xml
RUN mvn dependency:go-offline -B --fail-never
From dependencies as intermediate
From Tomcat
RUN git pull repo.git (whatsoever)
RUN mvn package
アイデアは、Mavenがすぐに使用できる別のイメージにすべての依存関係を保持することです
まだ遭遇していない他のシナリオかもしれませんが、このソリューションは、なぜJavaが今日の無駄のない世界でこんなに太ったクジラになったのか想像できないたびに3GBのゴミをダウンロードすることから少し安心します
ここでの他の答えが最適だとは思わない。たとえば、 mvn verify
answerは次のフェーズを実行し、依存関係を解決するだけではありません。
validate-プロジェクトが正しいこと、および必要なすべての情報が利用可能であることを検証します
コンパイル-プロジェクトのソースコードをコンパイルします
test-適切な単体テストフレームワークを使用して、コンパイルされたソースコードをテストします。これらのテストでは、コードをパッケージ化またはデプロイする必要はありません
パッケージ-コンパイルされたコードを取得し、JARなどの配布可能な形式でパッケージ化します。
検証-統合テストの結果をチェックして、品質基準が満たされていることを確認します
依存関係のみを解決したい場合は、これらのすべてのフェーズとそれに関連する目標を実行する必要はありません。
依存関係のみを解決する場合は、 dependency:go-offline
目標:
FROM maven:3-jdk-12
WORKDIR /tmp/example/
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src/ src/
RUN mvn package
Docker v18.03
以降では、他の回答で言及されたボリュームの代わりに BuildKit を使用できます。ビルド間で保持できるキャッシュをマウントでき、対応する.m2/repository
のコンテンツを毎回ダウンロードすることを回避できます。
Dockerfileがプロジェクトのルートにあると仮定します。
# syntax = docker/dockerfile:1.0-experimental
FROM maven:3.6.0-jdk-11-slim AS build
COPY . /home/build
RUN mkdir /home/.m2
WORKDIR /home/.m2
USER root
RUN --mount=type=cache,target=/root/.m2 mvn -f /home/build/pom.xml clean compile
target=/root/.m2
は、MavenイメージDockerfileの指定された場所にキャッシュをマウントします docs 。
ビルドするには、次のコマンドを実行できます。
DOCKER_BUILDKIT=1 docker build --rm --no-cache .
BuildKitの詳細については、 こちら をご覧ください。
Maven依存関係をキャッシュする方法は2つあります。
ビルドではなく、コンテナ実行の一部として「mvn verify」を実行し、ボリュームから.m2をマウントすることを確認します。
これは効率的ですが、クラウドビルドおよび複数のビルドスレーブではうまく機能しません
「依存関係キャッシュコンテナー」を使用し、定期的に更新します。方法は次のとおりです。
a。 pomをコピーしてオフライン依存関係を構築するDockerfileを作成します。
FROM maven:3.5.3-jdk-8-Alpine
WORKDIR /build
COPY pom.xml .
RUN mvn dependency:go-offline
b。 「Deps:latest」として定期的に(夜間など)ビルドします
c。別のDockerfileを作成して、コミットごとにシステムを実際に構築し(できればマルチステージを使用します)-FROM Depsであることを確認します。
このシステムを使用すると、ほとんど十分なキャッシュを備えた、高速で再構築可能なビルドができます。
この問題はほんの少し前にありました。 Web上には多くのソリューションがありますが、私のために働いたのはmavenモジュールディレクトリのボリュームを単にマウントすることです:
mkdir /opt/myvolumes/m2
次に、Dockerfileで:
...
VOLUME /opt/myvolumes/m2:/root/.m2
...
より良いソリューションがありますが、それほど簡単ではありません。
このブログ投稿では、すべてをキャッシュするのに役立ちます。
https://keyholesoftware.com/2015/01/05/caching-for-maven-docker-builds/