简体   繁体   English

如何使用docker volume在Tomcat中部署war / jar

[英]How to use docker volume to deploy war / jar in Tomcat

Is it possible to deploy some java war or jar file in Tomcat? 是否可以在Tomcat中部署一些java war或jar文件? I looking for a lot of tutorials and the only solution I found is copy project war file into /usr/local/tomcat/webapps/ . 我找了很多教程,我找到的唯一解决方案是将项目war文件复制到/usr/local/tomcat/webapps/

I actually used that solution but I would like to improve my dockerisation. 我实际上使用了这个解决方案,但我想改进我的dockerisation。 My primary goal is when I run my 2 images (application in tomcat and db image) with docker-compose I want to use my local war file of target folder in tomcat, and, when I build war again after the code changed, that change will be reflected without stopping containers, removing, and rebuilding. 我的主要目标是当我使用docker-compose运行我的2个图像(tomcat和db image中的应用程序)时,我想在tomcat中使用目标文件夹的本地war文件,当我在代码更改后再次构建war时,将在不停止容器,移除和重建的情况下进行反映。 Can you help to do that? 你可以帮忙吗? My attempts failed. 我的尝试失败了。 I want it just for development purpose. 我希望它仅用于开发目的。

Here is my docker-compose.yml 这是我的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"

and Dockerfile for that tomcat 和那个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"]

With configuration above applicaton starts, but when I run mvn clean package application is not loaded anymore 使用上面的配置应用启动,但是当我运行mvn clean package应用程序不再被加载

EDIT 编辑

I checked log of tomcat container and I found this error: 我检查了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

this error happened when I wanted to try restart container when new war is builded. 当我想在新战争建立时尝试重启容器时发生了这个错误。

You have two separate problems: 你有两个不同的问题:

  1. Depending on what command you use, Maven might well remove and recreate your target directory, which will leave the old, removed target directory still opened for the volume mount, by the Docker process. 根据您使用的命令,Maven可能会删除并重新创建target目录,这将使Docker进程仍然为卷装入打开旧的已删除target目录。 Your old file will be removed, and the new file created into a new directory which Docker has no idea about. 您的旧文件将被删除,新文件将创建到Docker不知道的新目录中。

  2. When Maven builds a new WAR ZIP file, your servlet runner might notice the new file mid-build, and try to open a half-baked WAR, which would of course end in failure. 当Maven构建一个新的WAR ZIP文件时,你的servlet运行器可能会注意到中间构建的新文件,并尝试打开一个半生不熟的WAR,这当然会以失败告终。

I suggest that you create a separate, at least semi-permanent directory, not in the target tree, for the purpose of being mounted by Docker. 我建议您创建一个单独的,至少是半永久性的目录,而不是在target树中,以便由Docker挂载。 Create a new Maven profile in your pom.xml file, and add a build target which copies your WAR file, after it's done being built, into that new directory, which you mount as Tomcat's webapps inside your container. pom.xml文件中创建一个新的Maven配置文件,并添加一个构建目标,在构建完成后将其复制到新目录中,该目录将作为Tomcat的webapps挂载到容器中。

Edit: Here's a solution which doesn't depend on the particular manner in which the virtualization system used by Docker might implement volume file transfer on any particular platform. 编辑:这是一个解决方案,它不依赖于Docker使用的虚拟化系统在任何特定平台上实现卷文件传输的特定方式。

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

pom.xml snippet: 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 snippet: 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 : 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 : 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>

Then: 然后:

mvn package

mvn cargo:redeploy

Edit 2: As a response to "... is possible to do that without anz additional plugin?" 编辑2:作为回应“......如果没有额外的插件可以做到这一点吗?” in the comments: 在评论中:

Yes. 是。 If you: 如果你:

  1. Are running Windows on the host, and a Tomcat Docker image inside a virtual machine. 在主机上运行Windows,在虚拟机中运行Tomcat Docker镜像。

  2. Want to accomplish this through the use of volumes and no extra plugins. 希望通过使用卷来实现这一点,而不需要额外的插件。

... you can go about it like this: ......你可以这样做:

  1. Mount, for example, C:/example/wars to the Docker containers' /tmp/example/wars . 例如,将C:/example/wars挂载到Docker容器' /tmp/example/wars

  2. Run mvn package . 运行mvn package

  3. Copy the WAR file, say with a script which does the whole thing, from the build to the deploy, to the directory C:/example/wars . 复制WAR文件,比如使用完成整个操作的脚本,从构建到部署,再复制到目录C:/example/wars We are only taking this step because you might run mvn clean which will remove the target directory, and if you've mounted it directly, Docker might not notice the new target directory created by mvn . 我们只采取这一步,因为您可能运行mvn clean将删除target目录,如果您直接挂载它,Docker可能不会注意到mvn创建的新target目录。

  4. Look up your container name with docker ps . 使用docker ps查找容器名称。

  5. Run the command, again from your deploy script, docker exec $CONTAINER mv /tmp/example/wars/*.war /usr/local/tomcat/webapps/ which will copy, inside the Docker container, inside the virtual machine, the complete, non-broken WAR ZIP file into the deployment directory. 再次从您的部署脚本, docker exec $CONTAINER mv /tmp/example/wars/*.war /usr/local/tomcat/webapps/运行该命令,它将在Docker容器内复制到虚拟机内部,完成,将未破坏的WAR ZIP文件放入部署目录。

Your problem seems simpler than it looks. 你的问题似乎比看上去简单。 First of all, yes you can do that, a pretty good and production grade example here: https://hub.docker.com/r/esystemstech/liferay 首先,是的,你可以做到这一点,这是一个非常好的生产等级示例: https//hub.docker.com/r/esystemstech/liferay

About your docker file, this line does nothing for you, besides hiding the files under a layer: 关于您的docker文件,除了将文件隐藏在图层下之外,此行不会为您做任何事情:

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

which means this is not even saving space. 这意味着这甚至不能节省空间。 Now, consider mounting the folder as your volume, instead of the file. 现在,考虑将文件夹作为卷而不是文件。 You can also leave the context inside the file. 您也可以将上下文保留在文件中。 and finally just check if the timing is correct, I mean, if you are rebooting after the packing operation. 最后只是检查时间是否正确,我的意思是,如果你在打包操作后重新启动。 I am saying that because if: 我这样说是因为:

Caused by: java.util.zip.ZipException: error in opening zip file

For what I am seeing in your examples, you do not even need a Dockerfile, you can replace the build with an image in your docker compose file, and just mount the volume. 对于我在示例中看到的内容,您甚至不需要Dockerfile,可以使用docker compose文件中的image替换build ,然后安装卷。 Unless you are doing extra stuff inside the docker file. 除非你在docker文件中做了额外的事情。

While this does NOT answer your question exactly, there is an alternative to consider that does not require you to have a different development configuration than for test or production. 虽然这不能完全回答您的问题,但有一种替代方案可以考虑,不需要您具有与测试或生产不同的开发配置。

Just build your war file locally and then docker cp it: 只需在本地构建你的war文件然后docker cp

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM