web-dev-qa-db-ja.com

Dockerボリュームを使用してTomcatでwar / jarを展開する方法

TomcatにJava warまたはjarファイルをデプロイできますか?多くのチュートリアルを探していますが、プロジェクトwarファイルを/usr/local/Tomcat/webapps/にコピーするだけです。

実際にそのソリューションを使用しましたが、Dockerizationを改善したいと思います。私の主な目標は、2つのイメージ(Tomcatのアプリケーションとdbイメージ)をdocker-composeで実行することです。Tomcatのターゲットフォルダーのローカルwarファイルを使用します。コンテナを停止、削除、再構築せずに反映されます。それを手伝ってくれる?私の試みは失敗しました。開発目的のためだけに欲しい。

これが私のdocker-compose.ymlです

version: '3'

services:

  Tomcat-service:
    build:
      context: ../
      dockerfile: docker/app/Dockerfile
    volumes:
      - D:\myproj\target\app.war:/usr/local/Tomcat/webapps/ROOT.war
    ports:
      - "8080:8080"
    depends_on:
      - "db-service"

  db-service:
    build: ./database
    ports:
      - "5433:5432"

そのTomcatのDockerfile

FROM Tomcat:8.0-jre8
RUN rm -rvf /usr/local/Tomcat/webapps/ROOT
COPY ./docker/app/context.xml /usr/local/Tomcat/conf/
# with following copy command it works, but when I rebuild war file, I need stop docker-compose and build and run it again .. I want use volume instead of copy war
#COPY ./pnp-web/target/pnp.war /usr/local/Tomcat/webapps/ROOT.war
EXPOSE 8080
CMD ["catalina.sh", "run"]

上記の設定ではアプリケーションが起動しますが、実行するとmvn clean packageアプリケーションがロードされなくなります

編集

Tomcatコンテナのログを確認したところ、次のエラーが見つかりました。

Tomcat-cont       | 10-Jul-2018 08:20:36.754 INFO [localhost-startStop-1] org.Apache.catalina.startup.HostConfig.deployWAR Deploying web application archive /usr/local/Tomcat/webapps/ROOT.war
Tomcat-cont       | 10-Jul-2018 08:20:36.858 SEVERE [localhost-startStop-1] org.Apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start:
Tomcat-cont       |  org.Apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[]]
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:162)
Tomcat-cont       |     at org.Apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.Java:755)
Tomcat-cont       |     at org.Apache.catalina.core.ContainerBase.addChild(ContainerBase.Java:731)
Tomcat-cont       |     at org.Apache.catalina.core.StandardHost.addChild(StandardHost.Java:717)
Tomcat-cont       |     at org.Apache.catalina.startup.HostConfig.deployWAR(HostConfig.Java:973)
Tomcat-cont       |     at org.Apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.Java:1850)
Tomcat-cont       |     at Java.util.concurrent.Executors$RunnableAdapter.call(Executors.Java:511)
Tomcat-cont       |     at Java.util.concurrent.FutureTask.run(FutureTask.Java:266)
Tomcat-cont       |     at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1149)
Tomcat-cont       |     at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:624)
Tomcat-cont       |     at Java.lang.Thread.run(Thread.Java:748)
Tomcat-cont       | Caused by: org.Apache.catalina.LifecycleException: Failed to start component [org.Apache.catalina.webresources.StandardRoot@51f50cb1]
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:162)
Tomcat-cont       |     at org.Apache.catalina.core.StandardContext.resourcesStart(StandardContext.Java:5016)
Tomcat-cont       |     at org.Apache.catalina.core.StandardContext.startInternal(StandardContext.Java:5149)
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
Tomcat-cont       |     ... 10 more
Tomcat-cont       | Caused by: org.Apache.catalina.LifecycleException: Failed to initialize component [org.Apache.catalina.webresources.JarResourceSet@20e48a4a]
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.init(LifecycleBase.Java:107)
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:135)
Tomcat-cont       |     at org.Apache.catalina.webresources.StandardRoot.startInternal(StandardRoot.Java:722)
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.start(LifecycleBase.Java:145)
Tomcat-cont       |     ... 13 more
Tomcat-cont       | Caused by: Java.lang.IllegalArgumentException: Java.util.Zip.ZipException: error in opening Zip file
Tomcat-cont       |     at org.Apache.catalina.webresources.AbstractSingleArchiveResourceSet.initInternal(AbstractSingleArchiveResourceSet.Java:142)
Tomcat-cont       |     at org.Apache.catalina.util.LifecycleBase.init(LifecycleBase.Java:102)
Tomcat-cont       |     ... 16 more
Tomcat-cont       | Caused by: Java.util.Zip.ZipException: error in opening Zip file
Tomcat-cont       |     at Java.util.Zip.ZipFile.open(Native Method)
Tomcat-cont       |     at Java.util.Zip.ZipFile.<init>(ZipFile.Java:225)
Tomcat-cont       |     at Java.util.Zip.ZipFile.<init>(ZipFile.Java:155)
Tomcat-cont       |     at Java.util.jar.JarFile.<init>(JarFile.Java:166)
Tomcat-cont       |     at Java.util.jar.JarFile.<init>(JarFile.Java:130)
Tomcat-cont       |     at org.Apache.Tomcat.util.compat.JreCompat.jarFileNewInstance(JreCompat.Java:170)
Tomcat-cont       |     at org.Apache.Tomcat.util.compat.JreCompat.jarFileNewInstance(JreCompat.Java:155)
Tomcat-cont       |     at org.Apache.catalina.webresources.AbstractSingleArchiveResourceSet.initInternal(AbstractSingleArchiveResourceSet.Java:139)
Tomcat-cont       |     ... 17 more
Tomcat-cont       |
Tomcat-cont       | 10-Jul-2018 08:20:36.859 SEVERE [localhost-startStop-1] org.Apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive /usr/local/Tomcat/webapps/ROOT.war
Tomcat-cont       |  Java.lang.IllegalStateException: ContainerBase.addChild: start: org.Apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].Stand
ardContext[]]
Tomcat-cont       |     at org.Apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.Java:759)
Tomcat-cont       |     at org.Apache.catalina.core.ContainerBase.addChild(ContainerBase.Java:731)
Tomcat-cont       |     at org.Apache.catalina.core.StandardHost.addChild(StandardHost.Java:717)
Tomcat-cont       |     at org.Apache.catalina.startup.HostConfig.deployWAR(HostConfig.Java:973)
Tomcat-cont       |     at org.Apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.Java:1850)
Tomcat-cont       |     at Java.util.concurrent.Executors$RunnableAdapter.call(Executors.Java:511)
Tomcat-cont       |     at Java.util.concurrent.FutureTask.run(FutureTask.Java:266)
Tomcat-cont       |     at Java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.Java:1149)
Tomcat-cont       |     at Java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.Java:624)
Tomcat-cont       |     at Java.lang.Thread.run(Thread.Java:748)
Tomcat-cont       |
Tomcat-cont       | 10-Jul-2018 08:20:36.860 INFO [localhost-startStop-1] org.Apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive /usr/local/Tomcat/webapps/ROOT.war has finish
ed in 105 ms

このエラーは、新しい戦争が構築されたときにコンテナを再起動しようとしたときに発生しました。

15
Denis Stephanov

次の2つの問題があります。

  1. 使用するコマンドによっては、Mavenはtargetディレクトリを削除して再作成する場合があります。これにより、Dockerプロセスによって、ボリュームマウント用に開いた古いtargetディレクトリが開かれたままになります。古いファイルは削除され、新しいファイルはDockerが知らない新しいディレクトリに作成されます。

  2. Mavenが新しいWAR Zipファイルをビルドすると、サーブレットランナーがビルド中に新しいファイルに気づき、中途半端なWARを開こうとすることがありますが、これはもちろん失敗に終わります。

Dockerでマウントするために、targetツリーではなく、少なくとも半永久的なディレクトリを別に作成することをお勧めします。 pom.xmlファイルに新しいMavenプロファイルを作成し、ビルド後にWARファイルをコピーするビルドターゲットを追加します。この新しいディレクトリは、コンテナ内のTomcat webappsとしてマウントします。 。

Edit:これは、Dockerが使用する仮想化システムが特定のプラットフォームでボリュームファイル転送を実装する特定の方法に依存しないソリューションです。

https://git.mikael.io/mikaelhg/docker-Tomcat-war-deploy-poc

pom.xmlスニペット:

        <plugin>
            <groupId>org.codehaus.cargo</groupId>
            <artifactId>cargo-maven2-plugin</artifactId>
            <version>1.6.8</version>
            <configuration>
                <container>
                    <containerId>Tomcat8x</containerId>
                    <type>remote</type>
                </container>
                <configuration>
                    <type>runtime</type>
                    <properties>
                        <cargo.protocol>http</cargo.protocol>
                        <cargo.hostname>localhost</cargo.hostname>
                        <cargo.servlet.port>8080</cargo.servlet.port>
                        <cargo.remote.username>admin</cargo.remote.username>
                        <cargo.remote.password>admin</cargo.remote.password>
                    </properties>
                </configuration>
                <deployer>
                    <type>remote</type>
                </deployer>
                <deployables>
                    <deployable>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>${project.artifactId}</artifactId>
                        <type>${project.packaging}</type>
                        <properties>
                            <context>/app</context>
                        </properties>
                    </deployable>
                </deployables>
            </configuration>
        </plugin>

docker-compose.ymlスニペット:

Tomcat:
  image: Tomcat:8
  volumes:
    - ./Tomcat-users.xml:/usr/local/Tomcat/conf/Tomcat-users.xml
    - ./manager-context.xml:/usr/local/Tomcat/webapps/manager/META-INF/context.xml
  ports:
    - "8080:8080"
  depends_on:
    - db

Tomcat-users.xml

<?xml version="1.0" encoding="UTF-8"?>
<Tomcat-users>
    <role rolename="manager-gui"/>
    <role rolename="manager-script"/>
    <user username="admin" password="admin" roles="manager-gui,manager-script"/>
</Tomcat-users>

manager-context.xml

<?xml version="1.0" encoding="UTF-8"?>
<Context antiResourceLocking="false" privileged="true">
    <Manager sessionAttributeValueClassNameFilter="Java\.lang\.(?:Boolean|Integer|Long|Number|String)|org\.Apache\.catalina\.filters\.CsrfPreventionFilter\$LruCache(?:\$1)?|Java\.util\.(?:Linked)?HashMap"/>
</Context>

次に:

mvn package

mvn cargo:redeploy

編集2:「...追加のプラグインなしでそれを行うことは可能ですか?」への応答としてコメントで:

はい。もし、あんたが:

  1. ホストでWindowsを実行し、仮想マシン内でTomcat Dockerイメージを実行しています。

  2. ボリュームを使用し、追加のプラグインを使用せずにこれを達成したい。

...次のように実行できます。

  1. たとえば、C:/example/warsをDockerコンテナの/tmp/example/warsにマウントします。

  2. mvn packageを実行します。

  3. ビルドからデプロイまでのすべてを実行するスクリプトを使用して、WARファイルをディレクトリC:/example/warsにコピーします。 mvn cleanを実行してtargetディレクトリを削除し、直接マウントした場合、Dockerは新しいtargetディレクトリが作成されないことに気付かない可能性があるため、この手順を実行するだけです。 mvnによって。

  4. docker psでコンテナ名を検索します。

  5. 展開スクリプトdocker exec $CONTAINER mv /tmp/example/wars/*.war /usr/local/Tomcat/webapps/から再度コマンドを実行します。このコマンドは、Dockerコンテナー内、仮想マシン内で、完全で破損していないWAR Zipファイルを展開ディレクトリにコピーします。

11
Mikael Gueck

あなたの問題は見た目よりも簡単に思えます。まず最初に、そうすることができます。かなり良い実稼働グレードの例をここに示します。 https://hub.docker.com/r/esystemstech/liferay

Dockerファイルについて、この行はレイヤーの下にファイルを隠すこと以外は何もしません:

RUN rm -rvf /usr/local/Tomcat/webapps/ROOT

これは、スペースを節約することさえできないことを意味します。ここで、ファイルではなく、フォルダーをボリュームとしてマウントすることを検討してください。ファイル内にコンテキストを残すこともできます。最後に、タイミングが正しいかどうかを確認します。つまり、パッキング操作後に再起動する場合です。私が言っているのは:

Caused by: Java.util.Zip.ZipException: error in opening Zip file

あなたの例で私が見ているのは、Dockerfileさえ必要ではなく、あなたのDocker構成ファイルでbuildimageに置き換えて、ボリュームをマウントするだけです。 dockerファイル内で余分な作業を行わない限り。

2
Victor

これはあなたの質問に正確に答えるものではありませんが、テストや本番用とは異なる開発構成を必要としないと考える代替案があります。

Warファイルをローカルでビルドしてからdocker cp それ:

docker cp D:\myproj\target\app.war My_Tomcat_Container:/usr/local/Tomcat/webapps/ROOT.war
2
JoeG