Tomcat and Docker, Why and how?

My rant about Docker and why it is great!

I am a huge fan of Docker and what it can do you for; especially in an industrial or entrepreneurial environment where scaling, stability, changes and frequent code releases are the norm.  The bullet points below are in my opinion the biggest advantages committing to containerizing your code/deployments.

  • Stability – You are developing your code for a controlled environment; once it works in your Docker container then you are set!  It does not matter where you host it or how each host is configured.  Your code will behave the same in dev as it does in uat and in your production environment.
  • Automated Scaling –  You will be hosting your docker container in a controller framework such as Kubernetes which boasts great features such as auto scaling, auto deployments, etc.  This is huge in regards to saving on resources; your instances will scale up and down with demand so you are not paying for servers that are not being used.  More importantly your product will not go down due to spiking demand (within reason of course).
  • Self Healing – Hosting vendors such as Google have built in self healing mechanisms directly into their platforms,  Lets say you wrote some code that slowly consumes disk space over time; eventually this will bring your Tomcat instance down.  Well if you have this containerized, the platform will immediately bring up a new “healthy” instance in its place to ensure constant up-time. (Just an FYI, I have never written bad code so this is only a hypothetical for me)
  • Managing Change – Change is a part of life so you better be ready for it.  Docker is quickly becoming a constant in the world of hosting so this naturally makes changing hosting companies a piece of cake.  I can confidently move my docker instances to virtually any Docker hosting company with 100% certainty that it will behave exactly the same as the prior host the first time.  Its almost the same concept of turning off a server, shipping to a new location and starting it up again; its just going to work with no additional effort.

The biggest disadvantage is really the easy of just creating something and pushing it out to a host; setting up your product on a hosting platform will take a little work especially if it is your first run at this.  This is by no means a reason to not at least give this a whirl; having this skill at your fingertips can easily give you a serious competitive advantage in the development and hosting industry.

Creating a Docker Instance with Tomcat (on a mac)

Lets go over how to create a docker instance that uses Tomcat and push a compiled Tomcat site to it.

The first thing we NEED to do is install the Docker tool on your machine; this will basically be the mechanism that we use to build and run our docker instances.  Without this we are nothing more than a boat without water.  Installing Docker is super easy; all you need to do is go to the docker website and download/run the latest stable version of “Docker Community Edition”.
Docker Download Link

After you download and setup Docker we will open a command prompt/terminal to test it out. When you open the command prompt, simply type “docker-machine ls” which shows you all docker virtual machines you have setup on your machine.  If you run this and you have no machines listed then you can simply run this following command to create a default instance/vm.

docker-machine create --driver virtualbox default

Now that we have Docker installed, we will need a quick website to run on it using Tomcat.  I will not go into how to build a quick Java site, instead I have a war file that you can download and use in your example. (I Love Apples Website – WAR File)  – Download and un-compress this file.

Next we will create our Docker file which is nothing more than a flat text file with instructions for the Docker application to use.  We will basically be telling docker about the instance we want it to create.

Go ahead and create a blank text file and add the following to it:

FROM tomcat:9-jre8

# Remove unneeded apps
RUN rm -rf /usr/local/tomcat/webapps/* 

# Add our app
ADD ILoveApples.war /usr/local/tomcat/webapps/

# Expose port 80
EXPOSE 80

CMD ["catalina.sh", "run"]

Well now we have created our Docker file and we have a website packaged into a “War” file; we are ready to start putting all of the pieces together and run this web server inside of a docker instance.  Now in this demo we will be running our docker instance inside of a virtual machine which should already be created if you follow the instructions on this blog.

Lets make sure our Docker machine is running.

docker-machine ls

Example output
NAME       ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
default    -        virtualbox   Running   tcp://192.168.99.100:2376           v1.12.5       

The 2 things we need to pay attention to here is the “NAME” and “STATE” columns.  If the state is not running then lets start our docker machine by typing the following command.  The name “default” is the name of the vm instance that will be used in our commands for the remainder of this blog.

docker-machine start default

Example output
Starting "default"...
(default) Check network to re-create if needed...
(default) Waiting for an IP...
Machine "default" was started.
Waiting for SSH to be available...
Detecting the provisioner...

This may take a few minutes to start if you are lacking the horse power in your computer; typically its pretty quick though. Now lets connect to our docker instance so that we can build and run our docker file.  This is key to do it this way because this is architecturally how it will be done at any hosting company you use for your website.

Here is how to connect to your docker instance.

docker-machine ssh default

Ok now even though you are technically on a virtual machine, you still have access to your files.  Lets assume that you put the War file and the Docker file we downloaded/created earlier into a folder called “Docker” in your Documents folder.  All we have to do is navigate to that folder and build your docker instance.

docker@default:~$ cd /Users/postalguy/Documents/Docker/

docker@default:/Users/postalguy/Documents/Docker$ docker build -f docker.txt --tag iloveapplesimage .
Sending build context to Docker daemon 10.75 kB
Step 1 : FROM tomcat:9-jre8
 ---> 6b4e3caa8fee
Step 2 : RUN rm -rf /usr/local/tomcat/webapps/*
 ---> 20acb70ce5b8
Step 3 : ADD ILoveApples.war /usr/local/tomcat/webapps/
 ---> a3b723cb8e70
Step 4 : EXPOSE 80
 ---> 89df30a414c3
Step 5 : EXPOSE 8080
 ---> 8b9395bb41b4
Step 6 : CMD catalina.sh run
 ---> d5f62504c882
Successfully built d5f62504c882

The docker build command is fairly easy; -f define the file we created, –tag is giving our docker instance a name we can use identify/control this instance.   The final “.” at this end says to look in this directory for everything we need.

If we run the following command we will see our docker image registered with this docker instance.

docker images
REPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
iloveapplesimage                        latest              d5f62504c882        2 days ago          366.6 MB

We are almost done now!  We just need to start our docker image inside of our docker virtual machine.  This is super duper easy!  We will use the docker run command; forwarding the outside 8080 port internally to our tomcat server on port 8080.  If you use the -d command in addition to this then it will run your instance in the background, releasing your console to run another command.  For testing purposes I like to keep it running on the same thread so I can see the output of my tomcat server.

docker run -p 8080:8080  iloveapplesimage

We are almost done now!  (I think I have said this before).  Lets open another fresh console; we just need to get the ip address of our docker machine that we started our docker image in.  Here is how we do this.

docker-machine ls
NAME       ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER        ERRORS
default    -        virtualbox   Running   tcp://192.168.99.100:2376           v1.12.5

So now we know our docker IP address, all we need to do is fire up a web browser and put the following URL in it!  (Substitute the IP from the URL  column above into your URL)

http://192.168.99.100:8080/ILoveApples/index.jsp

Well that is it!  Now every time you update your WAR file, just copy it into your docker folder and rebuild/rerun your docker instance.  Honestly it is a bit more work for deploying website BUT this is by far a sophisticated way to engineer your product for scalability/stability/predictability without having to over engineer your code and web server.  This will save you so many hours of heart ache, coding and engineering if you have a big project with a lot of demand and expectation to be ready for anything.  I personally love docker and have used it in professional environment; I have been able to scale up my servers globally/regionally, automatically fix bad instances and reduce overall cost…. All while I was sleeping!  Its all automated by your hosting company from here on out!

Real World Docker File Example

Now this was a super simple sample of a docker file.  I would like to leave you with one of my personal docker files that I have used on the google web platforms (which uses Kubernetes).

FROM tomcat:7-jre7
MAINTAINER ****@****.com

# Remove unneeded apps
RUN rm -rf /usr/local/tomcat/webapps/* 
RUN rm /usr/local/tomcat/conf/context.xml && rm /usr/local/tomcat/conf/server.xml

ADD tomcat-users.xml /usr/local/tomcat/conf/
ADD server.xml /usr/local/tomcat/conf/
ADD context.xml /usr/local/tomcat/conf/
ADD ****-8d3c9346814d.p12 /usr/local/tomcat/conf/
ADD ***.war /usr/local/tomcat/webapps/
ADD finalkey.jks /usr/local/tomcat/conf/
ADD cacerts /usr/local/tomcat/conf/

ENV DATASTORE_PRIVATE_KEY_FILE /usr/local/tomcat/conf/****-8d3c9346814d.p12
ENV DATASTORE_SERVICE_ACCOUNT 834******63-kb05f2sj2**********h246lh@developer.gserviceaccount.com
ENV JAVA_OPTS "-Djavax.net.ssl.keyStore=/usr/local/tomcat/conf/finalkey.jks -Djavax.net.ssl.keyStorePassword=***** -Djavax.net.ssl.trustStore=/usr/local/tomcat/conf/cacerts -Djavax.net.ssl.trustStorePassword=*****"
ENV CATALINA_OPTS "-Duser.timezone=UTC"
EXPOSE 80
EXPOSE 8080
EXPOSE 443

CMD ["catalina.sh", "run"]



This example above shows you how to import your own SSL keys, key store for connecting to external database server, exposing SSL and adding your own custom tomcat configuration files.