Application containers have gained tremendous popularity and their benefits for stateless microservices-style applications are well understood. However, vast majority of applications currently developed and managed by enterprise IT teams are traditional, multi-tier and stateful applications.
There is a common misconception that traditional applications cannot benefit from containerization and it is difficult to containerize them. In a recent post by Jim Bugwadia highlighted the benefits of containerizing stateful applications and discussed the best practices.
At a recent meetup more than 80% of attendees were interested in containerizing traditional applications.
In this post, I will discuss the steps involved in containerizing and deploying a traditional Java Spring based application.
The Spring PetClinic Application
PetClinic is a sample Spring-based Java application. For more details on the application you can take a look at the slides. The source code for PetClinic can be found on GitHub. At a high level, PetClinic is a Java application, packaged as a war file, that runs in an application server like Apache Tomcat. By default, PetClinic uses an in-memory database (HSQLDB) but can be configured to use MySQL in case a persistent database is needed.
The steps to containerize this application are:
- Create container image
- Identify runtime configuration
- Create application container
Creating the container image
First step is to create a container image but prior to that, it is important to decide how all the application components should be packaged. While it is possible to package the application and the database in the same container, the best practice is to separate the application and the database into different containers.
To create the container image, you first need to create a Dockerfile which contains all the instructions to assemble the image. The Dockerfile for PetClinic application is:
- Select a base image and add necessary packages – When creating any Dockerfile, you need to first select the base image to build the container image from. For PetClinic we can use the official Tomcat 7 image from Docker Hub. Additional operating system packages required for your application can be added to the base image.
- Add run script (optional) – Optionally, any scripts required to run the application can be added. The script can be used to perform any runtime configuration. In this example, we add a run script to configure Apache Tomcat users and run it.
- Add application war file – Next add the application war (web archive) file. The war file is typically generated by the build system. It needs to be copied to the ‘webapps’ folder so that Tomcat server can load it when it is started.
- Specify the run command – Finally specify the command to run the script added in step 2. This command will be executed when the container is started. Only one run command can be specified for a container image.
Once the Dockerfile is ready, the container image can be built using the command:
$ docker build -t petclinic .
where ‘petclinic’ is the image name.
Identifying runtime configuration
Now that the container image is ready, the runtime configuration needs to be identified.
Ports – Apache Tomcat base image used to create the container uses http port 8080 by default so we need to map port 8080 to the host port 8080 so that the application running in the container is accessible.
Database – As mentioned earlier, PetClinic application provides two options for database
- In-memory HSQL database – No additional configuration is needed as this database is used by default and the settings are in the data-access.properties file
- Persistent MySQL database – In order to use MySQL as the persistent data store, you need to specify additional properties for database configuration as JAVA_OPTS (JVM options) environment variable
- Environment variable:
JAVA_OPTS = -Djpa.database=MYSQL -Djdbc.driverClassName=com.mysql.jdbc.Driver -Djdbc.username=admin -Djdbc.password=password -Djdbc.url=’jdbc:mysql://<MySQL-IP-Address>:3306/petclinic?useUnicode=true&characterEncoding=UTF-8′ -Djdbc.initLocation=classpath:db/mysql/initDB.sql -Djdbc.dataLocation=classpath:db/mysql/populateDB.sql -Dhibernate.dialect=org.hibernate.dialect.MySQLDialect -Djava.security.egd=file:/dev/./urandom
- Environment variable:
Here we assume that MySQL database is already running. Just replace MySQL-IP-Address with the IP address of the MySQL server/container
Creating the application container
Now, you can start the application container using the command:
$ docker run -d -p 8080:8080 petclinic
Within a few seconds, the application should be up and running and you should able to access it on your host using port 8080.
To run PetClinic with MySQL database you can use the command:
$ docker run -d -p 8080:8080 –e JAVA_OPTS=-Djpa.database=MYSQL -Djdbc.driverClassName=com.mysql.jdbc.Driver -Djdbc.username=admin -Djdbc.password=password -Djdbc.url=jdbc:mysql://<MySQL-IP-Address>:3306/petclinic?useUnicode=true&characterEncoding=UTF-8 -Djdbc.initLocation=classpath:db/mysql/initDB.sql -Djdbc.dataLocation=classpath:db/mysql/populateDB.sql -Dhibernate.dialect=org.hibernate.dialect.MySQLDialect -Djava.security.egd=file:/dev/./urandom petclinic
Deploy using Nirmata
A simple way to deploy PetClinic and other containerized applications on any cloud is by using Nirmata. To deploy PetClinic, just connect your hosts, import the application blueprint from the catalog and deploy it to an environment! It is as simple as that! Try it out for yourself!
In this brief post, I showed how easy it is to containerize an existing application. Nirmata further simplifies the deployment and management such applications. Of course, for production deployments there are a few additional considerations like:
- Container Security – Attend our online meetup for a discussion related to container security.
- Container Storage
- Container Networking
- DevOps pipeline
We will also cover these topics in detail in future posts!