In a recent project, our team was required to deploy a web application using Docker. This presented a great opportunity to play around with Docker. In this article, I will go step-by-step on how to deploy a Java web application running on Apache Tomcat with PostgreSQL database server as a back-end, using Docker. A basic understanding of Docker fundamentals is assumed.

So now let's get started! At this point, what I have in hand is a WAR file of our web application, some PostgreSQL script files which contain database set-up scripts and of-course a Docker engine installed on my Windows machine. Now we want the environment to be as light as possible, so we will pull the PostgreSQL and Apache-Tomcat images running on Alpine Linux from the Docker Hub. Docker Hub is a repository of pre-created docker images for various applications. Also, to make the environment portable, we will write all the set-up instructions in a Dockerfile. This is the part about Docker I am really impressed with, instead of passing around a VM image of around 1GB or more, you just distribute the Dockerfile and related scripts/packages, and you're good to go! For our current task, we will create two separate Docker files - Dockerfile.db (Database related set-up) and Database.web (Application server setup).

Go ahead and fire-up the Docker Engine. You can lookup the current working directory for Docker using the command 'pwd'. Now create a new folder - 'Docker_Project'.
mkdir Docker_Project
cd Docker_Project
I also have a PostgreSQL script (db_setup.sql) that will create database objects and populate the tables, so I will copy it to the current folder - Docker_Project.

To configure the Database environment, we will create the Dockerfile.db file and write the relevant docker instructions. I will use the vi editor, but feel free to use any text editor that you feel comfortable with.
vi Dockerfile.db
Write the following script into the Dockerfile.db. The explanation of each line in the script is commented inline. FYI: The comments in a Dockerfile start with '#'.
# Pull up an Alpine-PostgreSQL image from Docker Hub
FROM kiasaki/alpine-postgres
Now, we want to tune the database image with PostgreSQL configurations and pre-load it with the tables and records. We have all this written in our database script db_setup.sql, but want docker to run this script at start-up. So for this we have to include the script file in the below location and tell docker to run it.
ADD db_setup.sql /docker-entrypoint-initdb.d/
RUN chmod 755 /docker-entrypoint-initdb.d/db_setup.sql
So when we run this image as a container, we will have all the configurations and tables created & populated with the initial data needed. That's it for the Database part! Don't forget to save and close the file.

Now let's create Dockerfile.web for the Apache Tomcat server setup. Remember to copy the WAR file to current working directory of Docker prompt.
vi Dockerfile.web
Write the following script into the Dockerfile.web.
# Pull up the Tomcat8 image from Docker Hub. As noted earlier, this image is also based on Alpine Linux.
FROM jeanblanchard/tomcat:8
# Add the WAR file to the Tomcat server.
ADD BankOfInsecurities.war /opt/tomcat/webapps/
Sometimes the Tomcat home path can be different, so let's make a little detour to get that part correct. In your docker console, run the following commands:
FROM jeanblanchard/tomcat:8
docker run -d jeanblanchard/tomcat:8
The above command will create a new container which will run the Tomcat server image. The next step is to open the container's bash/shell.
docker ps -a
# Copy the Container ID of the jeanblanchard/tomcat:8 image
docker exec -i -t {Container ID} /bin/sh
Once you notice the prompt, use the below command to find the Tomcat root directory. In my case the root path was /opt/tomcat/. So my WAR file must go to /opt/tomcat/webapps/
Ok so now that we have the correct Tomcat path, let's get back to where we were. Save and close the current file. At this point we have two files ready - Dockerfile.db and Dockerfile.web. Next, we will actually go and create Docker images from these files.

In the Docker console, run the below commands to create the PostgreSQL and Tomcat images.
docker build -q -t postgresql_image -f Dockerfile.db .
Don't forget the period at the end. It indicates the current directory relative to the current working directory of Docker prompt. In our case it is the 'Docker_Project'. That is where Docker will look for the 'Dockerfile.db' file. The above command will create an image with the name - 'postgresql_image'. Now run the below command to create another image for the Tomcat server.
docker build -q -t tomcat_image -f Dockerfile.web .

Finally it's time to run the images we created previously as Docker containers. Run the below commands in docker console to do that.
docker run --hostname postgresql_container --name postgresql_container
-p 5432:5432 -e POSTGRES_USER=db_user -e POSTGRES_PASSWORD=db_pwd -e POSTGRES_DB=db_name -d postgresql_image

The above command will run a light-weight PostgreSQL server inside the Docker container, and bind port 5432 of your host machine to this server, so it will look like the server is actually running on your host machine and not separately inside Docker engine. And of course we can change the port number to a different value. How cool is that! You would want to replace the variables - db_user, db_pwd and db_name with the actual username, password and database name of your database. After this, let's go ahead and create another container for our Tomcat server. Run the below command to do that.
docker run --name tomcat_container -d -p 8080:8080
--link postgresql_container:postgresql_container tomcat_image

The link parameter above will allow your Web container to communicate with the Database container. Also, if you're wondering about the -d parameter above, it runs the container in detached mode i.e. in background, so you can still type in new commands in the same Docker prompt.

And that's it folks. You can now access your web application in your browser like we normally do when we have an Application server running locally. Hope you found this article useful in one way or another.

P.S.: Please feel free to reach out to me about any discrepencies / errors in this article. You will find my contact details on the home page. Cheers!

© Manan Pancholi