web-dev-qa-db-fra.com

Comment utiliser Docker Volume pour déployer War / Jar dans Tomcat

Est-il possible de déployer des fichiers Java war ou jar dans Tomcat? Je cherche beaucoup de tutoriels et la seule solution que j'ai trouvée est de copier le fichier war du projet dans /usr/local/Tomcat/webapps/.

J'ai effectivement utilisé cette solution mais j'aimerais améliorer ma dockérisation. Mon objectif principal est lorsque j'exécute mes 2 images (application dans Tomcat et image db) avec docker-compose, je veux utiliser mon fichier de guerre local du dossier cible dans Tomcat, et, lorsque je recrée la guerre après la modification du code, ce changement sera reflété sans arrêter les conteneurs, ni les retirer ni les reconstruire. Pouvez-vous m'aider à faire cela? Mes tentatives ont échoué. Je le veux juste à des fins de développement.

Voici mon 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"

et Dockerfile pour ce Tomcat

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"]

Avec la configuration ci-dessus, l'applaton démarre, mais lorsque j'exécute mvn clean package l'application n'est plus chargée

MODIFIER

J'ai vérifié le journal du conteneur Tomcat et j'ai trouvé cette erreur:

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

cette erreur s'est produite lorsque j'ai voulu essayer de redémarrer le conteneur lors de la création d'une nouvelle guerre.

15
Denis Stephanov

Vous avez deux problèmes distincts:

  1. Selon la commande que vous utilisez, Maven pourrait bien supprimer et recréer votre répertoire target, ce qui laissera l'ancien répertoire target supprimé encore ouvert pour le montage du volume, par le processus Docker. Votre ancien fichier sera supprimé et le nouveau fichier créé dans un nouveau répertoire dont Docker n'a aucune idée.

  2. Lorsque Maven crée un nouveau fichier Zip WAR, votre exécuteur de servlet peut remarquer le nouveau fichier en cours de construction et essayer d'ouvrir un fichier WAR à moitié cuit, ce qui se terminera bien sûr par un échec.

Je vous suggère de créer un répertoire séparé, au moins semi-permanent, pas dans l'arborescence target, dans le but d'être monté par Docker. Créez un nouveau profil Maven dans votre pom.xml fichier, et ajoutez une cible de génération qui copie votre fichier WAR, une fois terminé, dans ce nouveau répertoire, que vous montez en tant que Tomcat webapps à l'intérieur de votre conteneur.

Edit: Voici une solution qui ne dépend pas de la manière particulière dont le système de virtualisation utilisé par Docker peut implémenter le transfert de fichiers en volume sur une plate-forme particulière.

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

pom.xml extrait:

        <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 extrait:

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>

Ensuite:

mvn package

mvn cargo:redeploy

Edit 2: En réponse à "... est-il possible de le faire sans plugin supplémentaire anz?" dans les commentaires:

Oui. Si vous:

  1. Exécutez Windows sur l'hôte et une image Tomcat Docker dans une machine virtuelle.

  2. Vous voulez accomplir cela grâce à l'utilisation de volumes et sans plugins supplémentaires.

... vous pouvez vous y prendre comme ceci:

  1. Montez, par exemple, C:/example/wars aux conteneurs Docker '/tmp/example/wars.

  2. Courir mvn package.

  3. Copiez le fichier WAR, disons avec un script qui fait tout, de la build au déploiement, dans le répertoire C:/example/wars. Nous ne prenons cette mesure que parce que vous pourriez exécuter mvn clean qui supprimera le répertoire target, et si vous l'avez monté directement, Docker peut ne pas remarquer le nouveau répertoire target créé par mvn.

  4. Recherchez le nom de votre conteneur avec docker ps.

  5. Exécutez à nouveau la commande à partir de votre script de déploiement, docker exec $CONTAINER mv /tmp/example/wars/*.war /usr/local/Tomcat/webapps/ qui copiera, à l'intérieur du conteneur Docker, à l'intérieur de la machine virtuelle, le fichier Zip WAR complet et non rompu dans le répertoire de déploiement.

11
Mikael Gueck

Votre problème semble plus simple qu'il n'y paraît. Tout d'abord, oui, vous pouvez le faire, un très bon exemple de qualité de production ici: https://hub.docker.com/r/esystemstech/liferay

À propos de votre fichier Docker, cette ligne ne fait rien pour vous, à part cacher les fichiers sous une couche:

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

ce qui signifie que ce n'est même pas économiser de l'espace. Maintenant, envisagez de monter le dossier comme volume, au lieu du fichier. Vous pouvez également laisser le contexte à l'intérieur du fichier. et enfin vérifiez simplement si le timing est correct, je veux dire, si vous redémarrez après l'opération d'emballage. Je dis cela parce que si:

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

Pour ce que je vois dans vos exemples, vous n'avez même pas besoin d'un Dockerfile, vous pouvez remplacer le build par un image dans votre fichier de composition Docker, et simplement monter le volume. Sauf si vous faites des choses supplémentaires dans le fichier docker.

2
Victor

Bien que cela ne réponde PAS exactement à votre question, il existe une alternative à considérer qui ne vous oblige pas à avoir une configuration de développement différente de celle du test ou de la production.

Créez simplement votre fichier de guerre localement, puis docker cp il:

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