web-dev-qa-db-ja.com

Javaアプリケーションのdockerコンテナを構築する方法

私がやりたいのは、私のJavaアプリケーションですが、ほとんどのコンパイル言語では以下の考慮事項が当てはまるはずです。=

問題

ビルドサーバーで、成果物としてアプリケーションのdockerイメージを作成します。そのためには、ビルドツール(通常はGradle、Maven、またはAnt)を使用してアプリケーションをコンパイルし、作成したJARファイルをdockerイメージに追加する必要があります。 DockerイメージでJARファイルを実行するだけなので、もちろん、Javaが既にインストールされているベースイメージから開始します。

これを行うには3つの方法があります。

ビルドツールにプロセスを制御させます

この場合、ビルドツールがプロセス全体を制御します。そのため、JARファイルを準備し、JARを作成した後、Dockerを呼び出してイメージを作成します。これは、JARが事前に作成されるため機能し、DockerはJARの作成に必要なビルドプロセスを忘れることがあります。

しかし、私のDockerfileはもはやスタンドアロンではありません。 Dockerが機能するためには、Dockerの外部で行う手順に依存します。 Dockerfileには、JARファイルをイメージにコピーすることになっているCOPYまたはADDステートメントがあります。 jarが事前に作成されていない場合、このステートメントは失敗します。そのため、Dockerfileを実行するだけでは機能しない場合があります。これは、DockerHubの自動ビルド機能など、現在のDockerfileを使用してビルドするサービスと統合する場合に問題になります。

dockerにビルドを制御させます

この場合、イメージの作成に必要なすべての手順がDockerfileに追加されるため、Dockerビルドを実行するだけでイメージを作成できます。

このアプローチの主な問題は、作成されているdockerイメージの外部で実行されるDockerfileコマンドに追加する方法がないことです。つまり、ソースコードとビルドツールをdockerイメージに追加し、イメージ内にJARファイルをビルドする必要があります。これにより、追加されたすべてのファイルが実行時に不要になるため、イメージが必要以上に大きくなります。これにより、画像にレイヤーが追加されます。

編集:

@ adrian-mouatがソースを追加し、アプリケーションをビルドし、1つのRUNステートメントでソースを削除すると指摘したように、Dockerイメージに不要なファイルとレイヤーを追加することを回避できました。これは、非常識な連鎖コマンドを作成することを意味します。

2つの別個のビルド

この場合、ビルドを2つに分割します。まず、ビルドツールを使用してJARファイルを作成し、リポジトリ(MavenまたはIvyリポジトリ)にアップロードします。次に、リポジトリからJARファイルを追加するだけの別個のDockerビルドをトリガーします。

結論

私の意見では、より良い方法はビルドツールにプロセスを制御させるでしょう。これにより、クリーンなDockerイメージが得られます。イメージは配信するものであるため、これは重要です。動作しない可能性のあるDockerfileを回避するには、ビルドの一部として作成する必要があります。そのため、誤ってそれを使用して壊れたビルドを開始することはありません。

しかし、これではDockerHubと統合できません。

質問

私が行方不明になっている別の方法はありますか?

42
Tobias Kremer

Dockerレジストリハブには Mavenイメージ があり、これを使用してJavaコンテナを作成できます。

このアプローチを使用すると、ビルドマシンにJavaまたはMavenが事前にインストールされている必要はありません。Dockerはビルドプロセス全体を制御します。

├── Dockerfile
├── pom.xml
└── src
    ├── main
    │   ├── Java
    │   │   └── org
    │   │       └── demo
    │   │           └── App.Java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── Java
            └── org
                └── demo
                    └── AppTest.Java

コンテナは次のように構築されます。

docker build -t my-maven .

そして、次のように実行します:

$ docker run -it --rm my-maven
0    [main] INFO  org.demo.App  - hello world

Dockerfile

FROM maven:3.3-jdk-8-onbuild
CMD ["Java","-jar","/usr/src/app/target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

更新

コンテナを最適化してソースを除外する場合は、ビルドされたjarのみを含むDockerfileを作成できます。

FROM Java:8
ADD target/demo-1.0-SNAPSHOT-jar-with-dependencies.jar /opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar
CMD ["Java","-jar","/opt/demo/demo-1.0-SNAPSHOT-jar-with-dependencies.jar"]

そして、2つのステップでコンテナを構築します。

docker run -it --rm -w /opt/maven \
   -v $PWD:/opt/maven \
   -v $HOME/.m2:/root/.m2 \
   maven:3.3-jdk-8 \
   mvn clean install

docker build -t my-app .

__

アップデート(2017-07-27)

Dockerに マルチステージビルド 機能が追加されました。これにより、Dockerはビルドツールを含むイメージを使用してコンテナーをビルドできますが、ランタイム依存関係のみを含むイメージを出力できます。

次の例は、この概念を示しています。最初のビルドフェーズのターゲットディレクトリからjarをコピーする方法に注意してください

FROM maven:3.3-jdk-8-onbuild 

FROM Java:8
COPY --from=0 /usr/src/app/target/demo-1.0-SNAPSHOT.jar /opt/demo.jar
CMD ["Java","-jar","/opt/demo.jar"]
29
Mark O'Connor

Java aplicationの構造)==

Demo
└── src
|    ├── main
|    │   ├── Java
|    │   │   └── org
|    │   │       └── demo
|    │   │           └── App.Java
|    │   └── resources
|    │       └── application.properties
|    └── test
|         └── Java
|               └── org
|                   └── demo
|                         └── App.Java  
├──── Dockerfile
├──── pom.xml

Dockerfileのコンテンツ

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

イメージをビルドして実行するコマンド

  • プロジェクトのディレクトリに移動します。D:/ Demoと言います。
$ cd D/demo
$ mvn clean install
$ docker build demo .
$ docker run -p 8080:8080 -t demo

コンテナが実行されているかどうかを確認します

$ docker ps

出力は

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES
55c11a464f5a        demo1               "Java -jar demo.jar"   21 seconds ago      Up About a minute   0.0.0.0:8080->8080/tcp   cranky_mayer
7
Riddhi Gohil

最も簡単な方法は、ビルドツールにプロセスを制御させるです。それ以外の場合は、ビルドツールのビルドファイルを維持する必要があります(pom.xmlはMavenまたはbuild.gradle Gradleの場合)およびDockerfile

Javaアプリ用のDockerコンテナを構築する簡単な方法は、 Jib を使用することです。これは、 Maven および Gradle プラグイン。

たとえば、Mavenを使用していて、実行中のDockerデーモンに対してコンテナーを構築する場合、次の1つのコマンドを実行するだけです。

mvn compile com.google.cloud.tools:jib-maven-plugin:0.9.2:dockerBuild

Dockerレジストリに直接ビルドする はJib dockerをインストールせずに、Dockerデーモン(ルート権限が必要)を実行するか、Dockerfile。また、より高速で、イメージを再現可能に構築します。

ジブの詳細については、Githubリポジトリをご覧ください: https://github.com/GoogleContainerTools/jib

3
Qingyang Chen

Spotify Docker Mavenプラグイン をしばらく使用しました。プラグインを使用すると、DockerビルドをMavenライフサイクルのフェーズにバインドできます。

例:ビルドされたアプリケーションをリソースとしてDockerビルドコンテキストに追加するプラグインを構成して、アプリケーションをパッケージ化(フェーズ:パッケージ)した後にDockerビルドを実行します。デプロイフェーズで、Dockerプッシュゴールを実行して、Dockerイメージをレジストリにプッシュします。これは、Nexusなどのリポジトリにアーティファクトを公開する通常のデプロイプラグインの横で実行できます。

その後、ビルドをCIサーバー上で2つの別個のジョブに分割しました。 Dockerはアプリケーションを実行する1つの方法にすぎないため(リリースされたアプリケーションはDockerだけでなく異なる環境でも必要になる場合があるため)、MavenビルドはDockerに依存するべきではありません。

そのため、最初のジョブはNexusでアプリケーションをリリースします(Mavenデプロイ経由)。 2番目のジョブ(最初のジョブのダウンストリーム依存関係である可能性があります)は、最新のリリースアーティファクトをダウンロードし、Dockerビルドを実行し、イメージをレジストリにプッシュします。最新のリリースをダウンロードするには、 Versions Maven Plugin (versions:use-latest-releases)と Maven Dependency Plugin (dependency:get anddependency:copy)を使用します。

2番目のジョブは、特定のバージョンのアプリケーションで開始して、古いリリースのDockerイメージを(再)ビルドすることもできます。さらに、両方のジョブを実行し、リリースバージョンまたはリリースアーティファクトをDockerビルドに渡すビルドパイプライン(Jenkins上)を使用できます。

2
gclaussn

いくつかのこと:

  • 追加した同じ命令でファイルを削除しても、イメージ内のスペースは消費されません。公式画像のDockerfilesのいくつかを見ると、ソースをダウンロードし、同じステップですべてを削除します(例 https://github.com/docker-library/python/blob /0fa3202789648132971160f686f5a37595108f44/3.5/slim/Dockerfile )。これは、いくつかの迷惑な体操を行う必要があることを意味しますが、それは完全に実行可能です。

  • 2つの別個のDockerfileに問題はありません。これの良いところは、JDKではなくJREを使用してjarをホストできることです。

1
Adrian Mouat

jarまたはwarパッケージを実行するための代替の使用法があります

  • jarをイメージに追加します。
  • javaのヒープサイズを設定します
  • エントリポイント経由でjarコマンドを実行します

サンプルdockerfile

FROM base
ADD sample.jar renamed.jar
ENV HEAP_SIZE 256m
ENTRYPOINT exec Java -Xms$HEAP_SIZE -Xmx$HEAP_SIZE -jar renamed.jar

さらに、Tomcatでのパッケージ展開の例

FROM Tomcat7
ADD sample.war ${CATALINA_HOME}/webapps/ROOT.war
CMD ${CATALINA_HOME}/bin/catalina.sh run

イメージとしてのdockerfilesの構築

cp Tomcat.dockerfile /workingdir/Dockerfile
docker build -t name /workingdir/Dockerfile .

リスト画像

docker images

画像を使用してコンテナを作成する

docker run --name cont_name --extra-vars var1=val1 var2=val2 imagename
0
pmoksuz

dockerfileを作成せずに、Jibツールを使用してJavaアプリケーションをコンテナ化します

Jibは、JavaアプリケーションのDockerイメージを構築するためにGoogleが管理するオープンソースJavaツールです。これにより、コンテナ化が簡素化されます。、dockerfileを記述する必要がないためです。そして実際には、自分でドッカー画像を作成して公開するためにドッカーをインストールする必要さえありません

GoogleはJibをMavenとGradleの両方のプラグインとして公開しています。 https://github.com/GoogleContainerTools/jib

Mavenプロジェクトを使用してJavaアプリケーションをコンテナー化する

https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#quickstart

Gradleプロジェクトを使用してJavaアプリケーションをコンテナー化する

https://github.com/GoogleContainerTools/jib/tree/master/jib-gradle-plugin#quickstart

0
anandchaugule

ここ 開発環境でどのように行うかを説明します。

  • Mavenを使用してローカルでwar/jarをビルドする
  • ローカルDockerフォルダーにコピーします
  • 実行 Intellij Dockerプラグイン war/jarを含むdockerイメージを作成し、アプリケーションサーバーを実行してリモートDockerサーバーにデプロイします

それが役に立てば幸い。

0
Eyal.Dahari