Mavenプロジェクトをドッキングする方法は?そしてそれを達成する方法はいくつありますか?


90

私はDockerを初めて使用します。多くのドキュメントを読み、多くの方法を試しましたが、Mavenを使用してJavaプロジェクトを実行する方法がわかりません。

  1. を使用してイメージを構築する必要がありDockerfileますか?
  2. ホストでMavenプロジェクトを実行する場合のコマンドはどのようなものDockerfileですか?

回答:


125

実例。

これはSpringBootチュートリアルではありません。これは、Dockerコンテナー内でMavenビルドを実行する方法に関する質問に対する更新された回答です。

もともと4年前に投稿された質問。

1.アプリケーションを生成します

SpringInitializerを使用してデモアプリを生成します

https://start.spring.io/

ここに画像の説明を入力してください

zipアーカイブをローカルに抽出します

2.Dockerfileを作成します

#
# Build stage
#
FROM maven:3.6.0-jdk-11-slim AS build
COPY src /home/app/src
COPY pom.xml /home/app
RUN mvn -f /home/app/pom.xml clean package

#
# Package stage
#
FROM openjdk:11-jre-slim
COPY --from=build /home/app/target/demo-0.0.1-SNAPSHOT.jar /usr/local/lib/demo.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","/usr/local/lib/demo.jar"]

注意

  • この例では、マルチステージビルドを使用しています。最初の段階は、コードをビルドするために使用されます。2番目のステージには、ビルドされたjarとそれを実行するためのJREのみが含まれます(jarがステージ間でどのようにコピーされるかに注意してください)。

3.イメージを作成します

docker build -t demo .

4.イメージを実行します

$ docker run --rm -it demo:latest

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

2019-02-22 17:18:57.835  INFO 1 --- [           main] com.example.demo.DemoApplication         : Starting DemoApplication v0.0.1-SNAPSHOT on f4e67677c9a9 with PID 1 (/usr/local/bin/demo.jar started by root in /)
2019-02-22 17:18:57.837  INFO 1 --- [           main] com.example.demo.DemoApplication         : No active profile set, falling back to default profiles: default
2019-02-22 17:18:58.294  INFO 1 --- [           main] com.example.demo.DemoApplication         : Started DemoApplication in 0.711 seconds (JVM running for 1.035)

その他

ローカルリポジトリを使用してjarをキャッシュするようにMavenビルドを最適化する方法については、Dockerハブのドキュメントをお読みください。

更新(2019-02-07)

この質問は現在4年前のものであり、その間にDockerを使用したアプリケーションの構築に大きな変化があったと言っても過言ではありません。

オプション1:多段階ビルド

この新しいスタイルにより、ビルドツールやソースコードをカプセル化しない、より軽量なイメージを作成できます。

ここでも、公式のMavenベースイメージを使用して、目的のバージョンのMavenを使用してビルドの最初のステージを実行します。ファイルの2番目の部分は、ビルドされたjarを最終的な出力イメージにアセンブルする方法を定義します。

FROM maven:3.5-jdk-8 AS build  
COPY src /usr/src/app/src  
COPY pom.xml /usr/src/app  
RUN mvn -f /usr/src/app/pom.xml clean package

FROM gcr.io/distroless/java  
COPY --from=build /usr/src/app/target/helloworld-1.0.0-SNAPSHOT.jar /usr/app/helloworld-1.0.0-SNAPSHOT.jar  
EXPOSE 8080  
ENTRYPOINT ["java","-jar","/usr/app/helloworld-1.0.0-SNAPSHOT.jar"]  

注意:

  • 私はGoogleのディストロレスベースイメージを使用しています。これは、Javaアプリに十分なランタイムを提供するように努めています。

オプション2:ジブ

私はこのアプローチを使用していませんが、Dockerfilesのような厄介なものを作成することなくイメージを構築できるため、調査する価値があるようです:-)

https://github.com/GoogleContainerTools/jib

プロジェクトには、コードのパッケージ化をMavenワークフローに直接統合するMavenプラグインがあります。


元の回答(完全を期すために含まれていますが、何年も前に書かれています)

新しい公式画像を使用してみてください。Maven用の画像があります。

https://registry.hub.docker.com/_/maven/

このイメージを使用して、ビルド時にMavenを実行し、コンパイル済みアプリケーションを作成したり、次の例のように、コンテナー内でMavenビルドを実行したりできます。

例1-コンテナー内で実行されているMaven

次のコマンドは、コンテナー内でMavenビルドを実行します。

docker run -it --rm \
       -v "$(pwd)":/opt/maven \
       -w /opt/maven \
       maven:3.2-jdk-7 \
       mvn clean install

ノート:

  • このアプローチの優れた点は、すべてのソフトウェアがコンテナー内にインストールされて実行されていることです。ホストマシンにDockerが必要なだけです。
  • このバージョンについてはDockerfileを参照してください

例2-Nexusを使用してファイルをキャッシュする

Nexusコンテナを実行する

docker run -d -p 8081:8081 --name nexus sonatype/nexus

「settings.xml」ファイルを作成します。

<settings>
  <mirrors>
    <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://nexus:8081/content/groups/public/</url>
    </mirror>
  </mirrors>
</settings>

次に、NexusコンテナーにリンクするMavenを実行して、依存関係がキャッシュされるようにします。

docker run -it --rm \
       -v "$(pwd)":/opt/maven \
       -w /opt/maven \
       --link nexus:nexus \
       maven:3.2-jdk-7 \
       mvn -s settings.xml clean install

ノート:

  • Nexusをバックグラウンドで実行する利点は、ローカルコンテナで実行されているMavenビルドに対して透過的に管理URLを介して他のサードパーティリポジトリを管理できることです。

これを使用して、gradleビルドのMaven Centralを置き換えることができますか?support.sonatype.com/entries/に記載されているように… mavenCentral()gradleの依存関係をに置き換えましたが、maven {url "http://nexus:8081..."解決の問題が発生しています。
mohamnag 2015年

@mohamnag正解です。上記のMavenの「設定」ファイルはまさにそれを実行し、すべてのMavenCentralリクエストをローカルのネクサスリポジトリにリダイレクトします。あなたはあなたが抱えている解決の問題の種類を概説する必要があります。何か可能性があります...たとえば、「nexus」ホストが適切に解決されるようにDockerリンクを設定しましたか?
マークオコナー2015年

私はすべてが大丈夫であることがわかりました、しかしネクサスはインデックスを構築するのに時間が必要であったか、何か他のものが問題を引き起こしました。また、インデックスの更新をトリガーしようとしたため、どちらの場合で問題が解決したかわかりません。しかし、ありがとう。
mohamnag 2015年

Nexus3はDockerコンテナとしても利用できるようになりました。「sonatype / nexus3」を使用–ThorbjørnRavn
Andersen

1
@avandeursen --linkパラメーターが非推奨になったことは正しいです(3年以上前に回答してください)。ただし、(私の意見では)より正しい解決策は、Dockerネットワークを作成し、その上で両方のコンテナーを実行することです。そうすれば、DockerのネイティブDNS機能を活用して、ネクサスコンテナを名前で参照し続けることができます。後で例を更新します
Mark O'Connor

47

多くの方法があるかもしれません..しかし、私は2つの方法に従って実装しました

与えられた例はMavenプロジェクトです。

1.MavenプロジェクトでDockerfileを使用する

次のファイル構造を使用します。

Demo
└── src
|    ├── main
|    │   ├── java
|    │       └── org
|    │           └── demo
|    │               └── Application.java
|    │   
|    └── test
|
├──── Dockerfile
├──── pom.xml

そして、Dockerfileを次のように更新します。

FROM java:8
EXPOSE 8080
ADD /target/demo.jar demo.jar
ENTRYPOINT ["java","-jar","demo.jar"]

プロジェクトフォルダに移動し、次のコマンドを入力すると、イメージを作成してそのイメージを実行できます。

$ mvn clean
$ mvn install
$ docker build -f Dockerfile -t springdemo .
$ docker run -p 8080:8080 -t springdemo

Dockerを使用してSpringBootでビデオを入手する

2.Mavenプラグインの使用

指定されたMavenプラグインをに追加します pom.xml

<plugin>
    <groupId>com.spotify</groupId>
    <artifactId>docker-maven-plugin</artifactId>
    <version>0.4.5</version>
        <configuration>
            <imageName>springdocker</imageName>
            <baseImage>java</baseImage>
            <entryPoint>["java", "-jar", "/${project.build.finalName}.jar"]</entryPoint>
            <resources>
                <resource>
                    <targetPath>/</targetPath>
                    <directory>${project.build.directory}</directory>
                    <include>${project.build.finalName}.jar</include>
                </resource>
            </resources>
        </configuration>
    </plugin>

プロジェクトフォルダに移動し、次のコマンドを入力すると、イメージを作成してそのイメージを実行できます。

$ mvn clean package docker:build
$ docker images
$ docker run -p 8080:8080 -t <image name>

最初の例では、Dockerfileを作成し、ベースイメージを提供し、jarを追加します。その後、dockerコマンドを実行して特定の名前のイメージを構築し、そのイメージを実行します。

2番目の例では、提供しているmavenプラグインを使用しているためbaseImageimageNameここでDockerfileを作成する必要はありません。mavenプロジェクトをパッケージ化した後、dockerイメージを取得し、そのイメージを実行するだけです。


エントリポイントを変更してアーティファクト名を指定するのではなく、次のようなアプローチを使用できます。alooma.com / blog / building - dockers -maven-dependency-pluginを使用して共通の名前を使用します。コンテナー自体がバージョン管理されているため、バージョン管理されたjarをDockerコンテナーに入れる必要はありません。
kboom 2017

14

経験則として、Maven(コードとすべての依存関係の両方を含むJAR)を使用してファットJARを構築する必要があります。

次に、要件に一致するDockerfileを作成できます(ファットJARを構築できる場合は、CentOSなどのベースOSとJVMのみが必要です)。

これは私がScalaアプリ(Javaベース)に使用するものです。

FROM centos:centos7

# Prerequisites.

RUN yum -y update
RUN yum -y install wget tar

# Oracle Java 7

WORKDIR /opt

RUN wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.oracle.com%2F; oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/7u71-b14/server-jre-7u71-linux-x64.tar.gz
RUN tar xzf server-jre-7u71-linux-x64.tar.gz
RUN rm -rf server-jre-7u71-linux-x64.tar.gz
RUN alternatives --install /usr/bin/java java /opt/jdk1.7.0_71/bin/java 1

# App

USER daemon

# This copies to local fat jar inside the image
ADD /local/path/to/packaged/app/appname.jar /app/appname.jar

# What to run when the container starts
ENTRYPOINT [ "java", "-jar", "/app/appname.jar" ]

# Ports used by the app
EXPOSE 5000

これにより、Java7でCentOSベースのイメージが作成されます。起動すると、アプリjarが実行されます。

デプロイする最良の方法は、Dockerレジストリを使用することです。これは、Dockerイメージ用のGithubのようなものです。

次のようなイメージを作成できます。

# current dir must contain the Dockerfile
docker build -t username/projectname:tagname .

次に、次の方法で画像をプッシュできます。

docker push username/projectname # this pushes all tags

イメージがDockerレジストリに登録されると、世界中のどこからでもプルして実行できます。

詳細については、Dockerユーザーガイド参照してください。

覚えておくべきこと

イメージ内にリポジトリをプルして、コンテナ実行の一部としてjarをビルドすることもできますが、コードが変更され、通知なしに別のバージョンのアプリを使用する可能性があるため、これは適切なアプローチではありません。

ファットジャーを作成すると、この問題が解消されます。


こんにちは。Dockerファイルの例を使用してイメージ内のファットjarをコピーしましたが、ローカルパスを指定してファットjarを見つけることができないため、ビルドが失敗します。target / app.jarのようなものですか?
user_mda 2015年

こんにちは、実行時にネクサスからアーティファクトをダウンロードする方法はありますか?jar自体への実際のリンクではなく、プロパティを使用してダウンロードするアーティファクトを指定するには?dockerfile内:RUN wget -O {project.build.finalname}.jar しかし、私は上記のjarファイル をnexusからダウンロードしたいと思います。
Pramod Setlur 2016

1
コードリポジトリにFATJARを含めるのは、私には時間がかかります。Mavenを使用してイメージを構築する方法はありますか?
woLfPwNeR 2016

1
ファットジャーにもいくつかの問題があり、特に署名されたジャーでは問題があります。
–ThorbjørnRavn Andersen 2017

1
経験則として、ファットjarを使用しないでください。このデータをマージする安全な方法がないため、jar内のマニフェストまたはその他のデータファイルに依存するパッケージは失敗する可能性があります。jar内のパスが一致するマニフェストファイルが競合し、最初または最後のいずれかが優先されます(どちらが優先されるかを思い出せません)。ファットjarの使用を検討する必要があるのは、依存関係のセットが非常に限られており、それらのjarに競合するマニフェストデータがないことをよく知っている場合のみです。それ以外の場合は、使用するように設計されているため(つまり、個別に)安全に使用してください。
PiersyP

3

これが私の貢献です。
DockerとMavenを活用するために存在するすべてのツール/ライブラリ/プラグインをリストするつもりはありません。いくつかの答えはすでにそれをしました。
代わりに、アプリケーションの類型とDockerfileの方法に焦点を当てます。
Dockerfileは本当にシンプルで重要なDockerの概念であり(すべての既知/公開イメージはそれに依存しています)、Dockerfilesの理解と使用を避けようとすることは、Dockerの世界に参入するためのより良い方法であるとは限らないと思います。

アプリケーションのDocker化は、アプリケーション自体と到達する目標によって異なります

1)インストール済み/スタンドアロンのJavaサーバー(Tomcat、JBossなど)で実行したいアプリケーションの場合

道路はより困難であり、それは複雑さを増し(サーバーを管理/保守する必要があります)、ビルド/デプロイ/アンデプロイの点で組み込みサーバーよりもスケーラビリティと速度が遅いため、理想的なターゲットではありません
しかし、レガシーアプリケーションの場合、それは最初のステップと見なされる可能性があります。
一般に、ここでの考え方は、サーバーのDockerイメージを定義し、デプロイするアプリケーションごとにイメージを定義することです。
アプリケーションのDockerイメージは期待されるWAR / EARを生成しますが、これらはコンテナーとして実行されず、サーバーアプリケーションのイメージは、これらのイメージによって生成されたコンポーネントをデプロイされたアプリケーションとしてデプロイします。
レガシーなものがたくさんあり、フルスプリングブート組み込みソリューションに移行するのが非常に難しい巨大なアプリケーション(数百万行のコード)の場合、これは本当に素晴らしい改善です。
Dockerのマイナーなユースケースであるため、このアプローチについては詳しく説明しませんが、これらの複雑なケースに直面している開発者にとって、いくつかの扉が開かれていることを知っておくとよいと思うので、そのアプローチの全体的なアイデアを公開したいと思いました。 Dockerを統合します。

2)サーバー自体を埋め込み/ブートストラップするアプリケーションの場合(サーバーが埋め込まれたSpring Boot:Tomcat、Netty、Jetty ...)

これはDockerの理想的なターゲットです。Spring Bootを指定したのは、それを行うのに非常に優れたフレームワークであり、保守性も非常に高いためですが、理論的には、他のJavaの方法を使用してそれを実現できます。
一般に、ここでの考え方は、デプロイするアプリケーションごとにDockerイメージを定義することです。
アプリケーションのDockerイメージは、JARまたはJAR /クラス/構成ファイルのセットを生成します。これらのイメージからコンテナーを作成して開始すると、アプリケーションでJVMが開始されます(javaコマンド)。
新しいアプリケーションや移行するのにそれほど複雑ではないアプリケーションの場合、スタンドアロンサーバーよりもその方法を優先する必要があります。これは、コンテナーを使用する標準的な方法であり、最も効率的な方法だからです。
そのアプローチについて詳しく説明します。

MavenアプリケーションのDocker化

1)スプリングブーツなし

アイデアは、アプリケーションのコンパイル済みクラスと必要なMaven依存関係の両方を含むMaven(MavenアセンブリプラグインとMavenシェードプラグインのヘルプ)を使用してファットjarを作成することです。
次に、2つのケースを特定できます。

  • アプリケーションがデスクトップまたは自律型アプリケーション(サーバーにデプロイする必要がない)の場合:アプリケーションのJava実行のようCMD/ENTRYPOINTに指定できますDockerfilejava -cp .:/fooPath/* -jar myJar

  • アプリケーションがサーバーアプリケーション(Tomcatなど)の場合、考え方は同じです。アプリケーションのファットjarを取得し、でJVMを実行しCMD/ENTRYPOINTます。ただし、ここでは重要な違いorg.apache.tomcat.embedがあります。メインアプリケーションの起動時に組み込みサーバーを起動するロジックと特定のライブラリ(ライブラリなど)を含める必要があります。herokuWebサイトに
    包括的なガイドがあります。 2番目のケース(サーバーアプリケーション)の場合、それは機能しますが、それはまっすぐではなく、エラーが発生しやすく、多くのことを行うSpringBootなどの成熟したフレームワークのフレームにアプリケーションを配置しないためあまり拡張可能なモデルではありませんあなたのためにこれらのもののそしてまた高レベルの拡張を提供します。
    最初のケース(自律型アプリケーション)の場合、これはDockerを使用するための簡単で効率的な方法です。

    ただし、これには利点があります。組み込みのTomcat APIを直接使用するため、自由度が高くなります。

2)スプリングブーツ付き

最後に、ここに行きます。
これは、シンプルで効率的であり、十分に文書化されています。
Maven / SpringBootアプリケーションをDockerで実行するためのアプローチは実際にはいくつかあります。
それらすべてを公開することは長く、おそらく退屈でしょう。
最適な選択は、要件によって異なります。
しかし、いずれにせよ、Dockerレイヤーに関するビルド戦略は同じように見えます。
マルチステージビルドを使用したいと考えています。1つは依存関係の解決とビルドをMavenに依存し、もう1つはアプリケーションの起動にJDKまたはJREに依存しています。

ビルドステージ(Mavenイメージ):

  • 画像へのpomコピー
  • 依存関係プラグインのダウンロード。
    それについては、mvn dependency:resolve-plugins連鎖mvn dependency:resolveして仕事をするかもしれませんが、常にではありません。
    どうして ?これらのプラグインとpackagefatjarをパッケージ化するための実行は、異なるアーティファクト/プラグインに依存している可能性があり、同じアーティファクト/プラグインであっても、これらは異なるバージョンをプルする可能性があります。したがって、mvnアプリケーションのパッケージ化に使用されるコマンドを正確に実行して(必要な依存関係を正確にプルします)、ソースのコンパイルをスキップし、ターゲットフォルダーを削除して処理を高速化し、そのステップでの望ましくないレイヤー変更の検出を防ぎます。
  • 画像へのソースコードのコピー
  • アプリケーションをパッケージ化する

実行ステージ(JDKまたはJREイメージ):

  • 前の段階から瓶をコピーします

ここに2つの例があります。

a)ダウンロードされたMaven依存関係のキャッシュなしの簡単な方法

Dockerfile:

########Maven build stage########
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app

#copy pom
COPY pom.xml .

#resolve maven dependencies
RUN mvn clean package -Dmaven.test.skip -Dmaven.main.skip -Dspring-boot.repackage.skip && rm -r target/

#copy source
COPY src ./src

# build the app (no dependency download here)
RUN mvn clean package  -Dmaven.test.skip

# split the built app into multiple layers to improve layer rebuild
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar

########JRE run stage########
FROM openjdk:11.0-jre
WORKDIR /app

#copy built app layer by layer
ARG DOCKER_PACKAGING_DIR=/app/target/docker-packaging
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/lib /app/lib
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/classes /app/classes
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/META-INF /app/META-INF

#run the app
CMD java -cp .:classes:lib/* \
         -Djava.security.egd=file:/dev/./urandom \
         foo.bar.MySpringBootApplication

そのソリューションの欠点は?pom.xmlに変更を加えると、Mavenの依存関係をダウンロードして保存するレイヤー全体が再作成されます。イメージのビルド中にMavenリポジトリマネージャーを使用しない場合、全体として、これは多くの依存関係を持つアプリケーション(およびSpring Bootが多くの依存関係をプルする)には受け入れられません。

b)ダウンロードされたMaven依存関係のキャッシュを使用したより効率的な方法

アプローチはここでも同じですが、DockerBuilderキャッシュにキャッシュされるMaven依存関係のダウンロードです。
キャッシュ操作はbuildkit(dockerの実験用API)に依存しています。
buildkitを有効にするには、環境変数DOCKER_BUILDKIT = 1を設定する必要があります(.bashrc、コマンドライン、dockerデーモンjsonファイルなど)。

Dockerfile:

# syntax=docker/dockerfile:experimental

########Maven build stage########
FROM maven:3.6-jdk-11 as maven_build
WORKDIR /app

#copy pom
COPY pom.xml .

#copy source
COPY src ./src

# build the app (no dependency download here)
RUN --mount=type=cache,target=/root/.m2  mvn clean package -Dmaven.test.skip

# split the built app into multiple layers to improve layer rebuild
RUN mkdir -p target/docker-packaging && cd target/docker-packaging && jar -xf ../my-app*.jar

########JRE run stage########
FROM openjdk:11.0-jre
WORKDIR /app

#copy built app layer by layer
ARG DOCKER_PACKAGING_DIR=/app/target/docker-packaging
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/lib /app/lib
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/BOOT-INF/classes /app/classes
COPY --from=maven_build ${DOCKER_PACKAGING_DIR}/META-INF /app/META-INF

#run the app
CMD java -cp .:classes:lib/* \
         -Djava.security.egd=file:/dev/./urandom \
         foo.bar.MySpringBootApplication
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.