私はDockerを初めて使用します。多くのドキュメントを読み、多くの方法を試しましたが、Mavenを使用してJavaプロジェクトを実行する方法がわかりません。
- を使用してイメージを構築する必要があり
Dockerfile
ますか? - ホストでMavenプロジェクトを実行する場合のコマンドはどのようなもの
Dockerfile
ですか?
回答:
これはSpringBootチュートリアルではありません。これは、Dockerコンテナー内でMavenビルドを実行する方法に関する質問に対する更新された回答です。
もともと4年前に投稿された質問。
SpringInitializerを使用してデモアプリを生成します
zipアーカイブをローカルに抽出します
#
# 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"]
注意
docker build -t demo .
$ 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ハブのドキュメントをお読みください。
この質問は現在4年前のものであり、その間にDockerを使用したアプリケーションの構築に大きな変化があったと言っても過言ではありません。
この新しいスタイルにより、ビルドツールやソースコードをカプセル化しない、より軽量なイメージを作成できます。
ここでも、公式の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"]
注意:
私はこのアプローチを使用していませんが、Dockerfilesのような厄介なものを作成することなくイメージを構築できるため、調査する価値があるようです:-)
https://github.com/GoogleContainerTools/jib
プロジェクトには、コードのパッケージ化をMavenワークフローに直接統合するMavenプラグインがあります。
新しい公式画像を使用してみてください。Maven用の画像があります。
https://registry.hub.docker.com/_/maven/
このイメージを使用して、ビルド時にMavenを実行し、コンパイル済みアプリケーションを作成したり、次の例のように、コンテナー内でMavenビルドを実行したりできます。
次のコマンドは、コンテナー内でMavenビルドを実行します。
docker run -it --rm \
-v "$(pwd)":/opt/maven \
-w /opt/maven \
maven:3.2-jdk-7 \
mvn clean install
ノート:
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
ノート:
多くの方法があるかもしれません..しかし、私は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プラグインを使用しているためbaseImage
、imageName
ここでDockerfileを作成する必要はありません。mavenプロジェクトをパッケージ化した後、dockerイメージを取得し、そのイメージを実行するだけです。
経験則として、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をビルドすることもできますが、コードが変更され、通知なしに別のバージョンのアプリを使用する可能性があるため、これは適切なアプローチではありません。
ファットジャーを作成すると、この問題が解消されます。
RUN wget -O {project.build.finalname}.jar
しかし、私は上記のjarファイル をnexusからダウンロードしたいと思います。
これが私の貢献です。
DockerとMavenを活用するために存在するすべてのツール/ライブラリ/プラグインをリストするつもりはありません。いくつかの答えはすでにそれをしました。
代わりに、アプリケーションの類型とDockerfileの方法に焦点を当てます。
Dockerfile
は本当にシンプルで重要なDockerの概念であり(すべての既知/公開イメージはそれに依存しています)、Dockerfile
sの理解と使用を避けようとすることは、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コマンド)。
新しいアプリケーションや移行するのにそれほど複雑ではないアプリケーションの場合、スタンドアロンサーバーよりもその方法を優先する必要があります。これは、コンテナーを使用する標準的な方法であり、最も効率的な方法だからです。
そのアプローチについて詳しく説明します。
1)スプリングブーツなし
アイデアは、アプリケーションのコンパイル済みクラスと必要なMaven依存関係の両方を含むMaven(MavenアセンブリプラグインとMavenシェードプラグインのヘルプ)を使用してファットjarを作成することです。
次に、2つのケースを特定できます。
アプリケーションがデスクトップまたは自律型アプリケーション(サーバーにデプロイする必要がない)の場合:アプリケーションのJava実行のようCMD/ENTRYPOINT
に指定できますDockerfile
:java -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イメージ):
mvn dependency:resolve-plugins
連鎖mvn dependency:resolve
して仕事をするかもしれませんが、常にではありません。package
fatjarをパッケージ化するための実行は、異なるアーティファクト/プラグインに依存している可能性があり、同じアーティファクト/プラグインであっても、これらは異なるバージョンをプルする可能性があります。したがって、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
mavenCentral()
gradleの依存関係をに置き換えましたが、maven {url "http://nexus:8081..."
解決の問題が発生しています。