Wednesday 3 May 2017

Deploying Java applications with Docker

Deploying Java applications with Docker
Docker allows you to create containers from your applications, for more information see: https://www.docker.io/. Docker can be used for many things, one of the options is to replace virtual machines with Docker containers. This article will explain how Docker can be used to setup Tomcat and deploy a Java application.

Why Docker?

Of course there are many tools available to automate the installation of servers and applications. Virtual machines can be used together with tools like Vagrant, Chef, Puppet and many more. But most of them  have their own DSL and some are not for free. That makes it harder to use them as developers and operations are unfamiliar with the tools and DSL’s. Docker has some specific commands, but for the installation of applications like the JDK or Tomcat standard OS commands can be used like apt-get, wget etcetera. Also Docker containers require less resources and startup faster than virtual images as this article will show.
Docker can be used to setup Java application servers for instance test and production machines (although for production it is better to wait until release 1). It is also possible to create a build environment with Jenkins, Nexus, Git, Sonar etc. One container should be used for every application to separate concerns.
The advantages of Docker are quite useful to overcome some of the technical challenges of continuous delivery. Versioning of Docker configuration files is quite easy. Another advantage is that environments can be setup from scratch for every deployment because Docker containers are quickly created and started.

Installing Docker

It is quite easy to install Docker. Instructions can be found on https://docs.docker.io/en/latest/installation. For this article Ubuntu 13.10 was chosen and the commands to install Docker are shown below.
sudo apt-get update
sudo apt-get install linux-image-extra-`uname -r`
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 36A1D7869245C8950F966E92D8576A8BA88D21E9
sudo sh -c "echo deb http://get.docker.io/ubuntu docker main > /etc/apt/sources.list.d/docker.list"
sudo apt-get update
sudo apt-get install lxc-docker
sudo docker run -i -t ubuntu /bin/bash
The last step will start a Docker container based on Ubuntu and start bash.

Adding your user to the Docker group

Root access is necessary to work with Docker, but you can also add your user to the docker group. After adding yourself to that group you no longer have to use the ‘sudo’ command.
sudo groupadd docker
sudo gpasswd -a your_username docker
sudo service docker restart
It is necessary to logout and login, restart Ubuntu or enter the command ‘newgrp docker’ before this works correctly.

Create a Docker container with Java and Tomcat

Create a file called ‘Dockerfile’ and add the content below. This is the configuration to install Java and Tomcat on a Ubuntu Saucy (13.10) Docker container that is provided by Docker. There are a lot of official and user supplied container configurations available at https://index.docker.io/. These containers can be used as the basis for your own container.
Dockerfile content:
FROM ubuntu:saucy
# Update Ubuntu
RUN apt-get update && apt-get -y upgrade
# Add oracle java 7 repository
RUN apt-get -y install software-properties-common
RUN add-apt-repository ppa:webupd8team/java
RUN apt-get -y update
# Accept the Oracle Java license
RUN echo "oracle-java7-installer shared/accepted-oracle-license-v1-1 boolean true" | debconf-set-selections
# Install Oracle Java
RUN apt-get -y install oracle-java7-installer
# Install tomcat
RUN apt-get -y install tomcat7
RUN echo "JAVA_HOME=/usr/lib/jvm/java-7-oracle" >> /etc/default/tomcat7
EXPOSE 8080
# Download Slashdot homepage
RUN mkdir /var/lib/tomcat7/webapps/slashdot
RUN wget http://www.slashdot.org -P /var/lib/tomcat7/webapps/slashdot
# Start Tomcat, after starting Tomcat the container will stop. So use a 'trick' to keep it running.
CMD service tomcat7 start && tail -f /var/lib/tomcat7/logs/catalina.out
Build the container using: ‘docker build –t tomcat7 .’. Do not forget to use the ‘.’ at the end. Instead of ‘tomcat7’ you can pick another name if you want. Now start the container using ‘docker run -p 8080:8080 -d tomcat7’. This command makes sure that port 8080 of the container is forwarded to your local port 8080.  After a few seconds the Slashdot page should be available at http://localhost:8080/slashdot/.

Container startup speed

A small test was executed to see how fast the container actually started. This test starts the Docker container and uses ‘wget’ to retrieve a page from within the container.
The commands are placed in a file called ‘dockerSpeed’, the content of the file is shown below:
docker run -p 8080:8080 -d tomcat7
wget localhost:8080/slashdot
The ‘time’ command can be used to see how fast the commands above are executed. Executing ‘time sh dockerSpeed’ gave the following result:
real        0m4.367s
user        0m0.011s
sys         0m0.008s
A few of these tests showed that the execution times were always between 4 and 5 seconds. That’s really quick if you compare that to starting virtual machines.

Container size

Docker creates a container for every command in the Dockerfile. If you have 12 commands in the Dockerfile, then Docker will create 12 containers. This allows the user to select an older container, for instance if you only need a container with Java, you could use that container instead of the one including Tomcat. Luckily only the difference between the containers is stored, which saves quite some diskspace.
Where Docker really wins from virtual machines is if you use multiple containers with the same base. For instance if you have 8 containers each using Ubuntu and Java. You could make a base container with Ubuntu and Java and create containers based on that base image. That way Ubuntu and Java are stored only once in a container, this results in fewer diskspace being used. With virtual machines, you would need that diskspace 8 times as it is not possible to create a common base.
This results in another good point of Docker. Separation of concerns is quite important and can be achieved easily, every application can be deployed in a separate container. So for a buildserver, you could make separate containers for Nexus, Jenkins, Git etcetera.
There are a few options to view the containers. The docker ‘ps’ command shows all active containers. Adding ‘-a’ to the ‘ps’ command also shows the stopped containers. Adding ‘-s’ to the ‘ps’ command shows the size of the containers. The output below from the ‘tomcat7’ container that was created in this article shows that most containers are quite small. Only the containers where bigger things are added like the JDK result in larger containers.
$ docker ps -a -s
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                    NAMES                    SIZE
3d9bd89b5ace        tomcat7:latest      /bin/sh -c service t   10 seconds ago      Up 10 seconds       0.0.0.0:8080->8080/tcp   grave_hawking            51.64 kB
fc116050d899        1ed13b7f9eb1        /bin/sh -c #(nop) CM   15 minutes ago      Exit 0                                       drunk_babbage            0 B
b788f8373ae7        5eb0489aed66        /bin/sh -c wget http   15 minutes ago      Exit 0                                       sleepy_nobel             4.613 kB
f465ff7c6cdf        a8febaa9ed55        /bin/sh -c wget http   15 minutes ago      Exit 0                                       hungry_lumiere           121.3 kB
d4dee2fd7c2f        1938691cd911        /bin/sh -c mkdir /va   15 minutes ago      Exit 0                                       dreamy_euclid            7 B
56f8bff7cfb9        d2e740750084        /bin/sh -c #(nop) EX   15 minutes ago      Exit 0                                       goofy_turing             0 B
1f8639f1841f        52d8cf48f2f3        /bin/sh -c echo "JAV   15 minutes ago      Exit 0                                       grave_bohr               2.074 kB
4cffeada2f59        8811557c9b1b        /bin/sh -c apt-get -   15 minutes ago      Exit 0                                       determined_ptolemy       11 MB
e6a24a05efb3        7d4e8d307140        /bin/sh -c apt-get -   16 minutes ago      Exit 0                                       nostalgic_wozniak        450 MB
090b2652f31e        9f35a5c15127        /bin/sh -c echo "ora   16 minutes ago      Exit 0                                       condescending_brattain   2.764 MB
743d10527376        cce7c0072447        /bin/sh -c apt-get -   16 minutes ago      Exit 0                                       sleepy_ritchie           179 kB
9da7cf4f4ca7        cea346235f02        /bin/sh -c add-apt-r   16 minutes ago      Exit 0                                       jovial_engelbart         863 B
d8c359bdd163        0dcc4e24ae2f        /bin/sh -c apt-get -   17 minutes ago      Exit 0                                       jolly_albattani          33.06 MB
7b184e8b6ece        ubuntu:13.10        /bin/sh -c apt-get u   17 minutes ago      Exit 0                                       trusting_shockley        25.18 MB
Another option is to view the images tree from Docker, the output for the ‘tomcat7’ container is shown below.
$ docker images -tree
??511136ea3c5a Virtual Size: 0 B
??1c7f181e78b9 Virtual Size: 0 B
??9f676bd305a4 Virtual Size: 178 MB Tags: ubuntu:13.10, ubuntu:saucy
??0dcc4e24ae2f Virtual Size: 215.6 MB
??cea346235f02 Virtual Size: 249 MB
??cce7c0072447 Virtual Size: 249 MB
??9f35a5c15127 Virtual Size: 249.2 MB
??7d4e8d307140 Virtual Size: 251.9 MB
??8811557c9b1b Virtual Size: 702.3 MB
??52d8cf48f2f3 Virtual Size: 713.7 MB
??d2e740750084 Virtual Size: 713.7 MB
??1938691cd911 Virtual Size: 713.7 MB
??a8febaa9ed55 Virtual Size: 713.7 MB
??5eb0489aed66 Virtual Size: 713.8 MB
??1ed13b7f9eb1 Virtual Size: 713.8 MB
??f846774ccd37 Virtual Size: 713.8 MB Tags: tomcat7:latest

Deploy a Java application in Tomcat

The example above used a simple HTML file from Slashdot. Of course that’s not enough, we want to deploy Java applications! That can be done quite easily, just add the following line to the Dockerfile just below the ‘wget’ command for Slashdot.
RUN wget http://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/sample.war -P /var/lib/tomcat7/webapps
Build a Docker container based on the new Dockerfile and run the container. Browsing to http://localhost:8080/sample/ will show the sample Tomcat web application.

Some useful Docker commands

Although Docker basics are fairly simple it still has a lot of options and useful commands.
Testing a bit with Docker will result in quite some containers. Stopping and starting them one by one is not really convenient. The following commands can be used to stop and remove all containers
docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)
Sometimes you create a container using a Dockerfile but then you realize the container is not working properly. With the command below you can login to the container and see what is going wrong.

docker run -i -t tomcat7 /bin/bash

1 comment:

User Interface(UI) for Docker, Portainer

Portainer gives you access to a central overview of your Docker host or Swarm cluster. From the dashboard, you can easily access any manag...