如何使用Docker卷在Tomcat中部署war / jar

时间:2018-07-10 07:54:43

标签: java docker tomcat docker-compose

是否可以在Tomcat中部署一些Java war或jar文件?我正在寻找很多教程,而我发现的唯一解决方案是将项目war文件复制到/usr/local/tomcat/webapps/

我实际上使用了该解决方案,但我想改善我的dockerisation。我的主要目标是当我使用docker-compose运行我的2个映像(tomcat和db映像中的应用程序)时,我想在tomcat中使用目标文件夹的本地war文件,并且当代码更改后再次构建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"]

通过上述配置,applicaton开始运行,但是当我运行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

当我想在构建新战争时尝试重新启动容器时发生此错误。

3 个答案:

答案 0 :(得分:9)

您有两个独立的问题:

  1. 根据您使用的命令,Maven可能会删除并重新创建您的target目录,这将使Docker仍为卷挂载打开的已删除的旧target目录仍处于打开状态处理。您的旧文件将被删除,新文件被创建到Docker不知道的新目录中。

  2. 当Maven生成新的WAR ZIP文件时,您的servlet运行程序可能会注意到新文件在生成过程中处于中间状态,并尝试打开未完成的WAR,这当然会以失败告终。

    < / li>

我建议您创建一个单独的至少半永久性的目录,而不是在target树中,以供Docker挂载。在您的pom.xml文件中创建一个新的Maven配置文件,并添加一个构建目标,该文件在完成构建后将WAR文件复制到该新目录中,并以Tomcat的webapps的形式安装在您的容器中。

编辑:这是一个不依赖于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目录{1}}。

  4. 使用mvn查找容器名称。

  5. 再次从部署脚本docker ps运行命令,该命令会将Docker容器中完整的WAR ZIP文件完整且不间断地复制到部署目录中。 / p>

答案 1 :(得分:1)

您的问题似乎比看起来简单。 首先,是的,您可以这样做,这里是一个很好的生产级示例: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 compose文件中将build替换为image,然后挂载该卷。除非您在docker文件中做其他事情。

答案 2 :(得分:0)

虽然这不能完全回答您的问题,但还有一种替代方法可以考虑,即您不需要具有与测试或生产不同的开发配置。

只需在本地构建战争文件,然后docker cp即可:

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