Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to deploy WAR files in docker image

What is the docker way to deploy java projects in a docker container?

Do I copy the war into webapps:

FROM jetty:9.2.10
MAINTAINER Me "[email protected]"
ADD ./target/*.war /var/lib/jetty/webapps/ROOT.war

or do I take the exploded war file:

FROM jetty:9.2.10
MAINTAINER Me "[email protected]"
ADD ./target/app-0.1.0.BUILD-SNAPSHOT /var/lib/jetty/webapps/ROOT

Normally one would deploy the sealed war file if it was a normal container, but with docker, that means pushing a 10-20MB file every time you make a small change whereas adding the exploded war would only push the difference - the .class file that has changed.

Are there any downsides to deploying the exploded war instead of the war file?

like image 423
Jan Vladimir Mostert Avatar asked May 15 '15 05:05

Jan Vladimir Mostert


People also ask

Where do I deploy a WAR file?

Perhaps the simplest way to deploy a WAR file to Tomcat is to copy the file to Tomcat's webapps directory. Copy and paste WAR files into Tomcat's webapps directory to deploy them. Tomcat monitors this webapps directory for changes, and if it finds a new file there, it will attempt to deploy it.


4 Answers

You should actually ALWAYS deploy the exploded .war.

There are two elements of speed to think about here:

  1. How fast is it to be able to push up your image to a container repository?

    and

  2. How quickly can a new instance of my container start serving requests? (important in an elastic-scaling environment)

The answer to both is the same: You are better off exploding the .war file when creating your container and NOT copying the .war file to it.

This has the following two very positive effects:

  1. It makes the differences between container versions much smaller, and so your upload time is less.
  2. It means that, when dynamically scaling to meet application demand, your new container instances don't have to unzip your .war file before they can start responding to requests.

For those of us burdened by slow-upload connections, it's also a great idea to use a CI server or even a cloud-hosted VM to build and push your docker images to dockerhub or another container registry. That way you can take advantage of gigabit-scale upload speeds.

like image 181
Ryan Kimber Avatar answered Oct 06 '22 10:10

Ryan Kimber


This is how I do it:

FROM tomcat:8.0 MAINTAINER David Ford <[email protected]> ENV DB_HOST mySqlServer ENV DB_USER joeBlow ENV DB_PASSWORD bla bla bla EXPOSE 8080 RUN rm -fr /usr/local/tomcat/webapps/ROOT COPY target/webapp /usr/local/tomcat/webapps/ROOT 

On my todo list: separate out the WEB_INF/lib dir into its own container.

like image 35
Dave Ford Avatar answered Oct 06 '22 09:10

Dave Ford


I wonder how you're using your images. Adding a 20MB file while building an image should almost be instant. Mayb you somehow building images during deployment, like AWS does when you give it a Dockerfile.

In any case, I think it depends on how you're deploying. If you're moving the images around yourself, I don't see a lot of difference between ADDing a .war file and an exploded WAR directory. I would say do what's convenient for you. However, if you sometimes run the app from Docker and sometimes from a .war (which might miss some of the point of Docker), you might as well use the .war all the time.

If you're deploying to something like AWS Elastic Beanstalk (something that pulls the image from a repository), which wants either a Dockerfile or a Dockerrun.aws.json file, then separating the image from what you actually deploy makes some sense (or it has made sense to me so far). This allows the container to stay the same, while updating your app can be just copying a .jar/.war file to the right location (which also might miss part of the point of Docker ;).

What I've been doing is creating a base image on Docker Hub and then using the Dockerrun.aws.json file to map in my app. That way, AWS does not need to build my image, just pull it. That's much faster and less costly ($). But it does separate my app from the image, which might complicate deployment in some circumstances. However, because my image is so stable, I generally just bundle a .jar file, a Dockerrun.aws.json file and a shell script into a .zip and upload it to AWS. Pretty easy I think.

My Dockerfile is pretty simple and really all I need for my Spring Boot app:

FROM java:8
VOLUME /tmp
VOLUME /app
EXPOSE 8080
ENTRYPOINT ["sh","/app/app.sh"]

You could do something similar and use the -v option, etc., to map volumes to your app, it's environment settings, etc. BTW, this image is available on Docker Hub.

like image 36
objectuser Avatar answered Oct 06 '22 09:10

objectuser


If you stumbled here, like I did, looking for how to simply get a WAR deployed in a container (using Apache Tomcat), and didn't care whether or not you have a Dockerfile.

A simple, elegant solution.

docker run \
-d \ # Detached mode, swap for -it if we want interactive.
-p 8080:8080  \
-v ${absolute_path_your_project_dir}/${MY_WAR}.war:/usr/local/tomcat/webapps/app.war \
tomcat:latest

Then navigate to http://localhost:8080/app/.

If that link doesn't work for you, be sure to change ...8080/app/ in the URL to whatever matches the .war name you gave in /usr/local/tomcat/webapps/app.war.

I also found that, while working through IntelliJ's Docker Plugin, it's easy to adapt this to Docker Plugins. Just be sure to put in your full path.

like image 43
NonCreature0714 Avatar answered Oct 06 '22 09:10

NonCreature0714