Dean Mraz

I am passionate about delivering ideas and spending most of my time on product management techniques.

September 27th 2016

Dockerize The Monolithic Application for Continuous Integration and Deployment

Monolithic apps without containerization is difficult to share, onboard developers and ship code into production. Virtual machine tools like vagrant is a step in the right direction but iterating with virtual machines are slow and time consuming. Docker containers are faster and lighter (file size). Plus, its easier to ship containers then it is a full virtual machine.

The goal of this post is to provide high level steps to move software towards Docker, Continuous Integration and Deployment. I started my journey with Docker 3 years ago and believe its the best path for any software project. I hope this post can enlighten others on their journey to containerizing their Monolithic App with Docker.

Where to begin?

  1. Development Environment
  2. Continuous Integration
  3. Production
  4. Continuous Deployment

Development Environment

  1. Create a docker folder in your monolithic application. The Dockerfile and file configuration will be stored there. You may want a folder per container. Extend from the official docker containers. There are requirements on running containers the "Docker Way," so using the official containers will ensure that. https://hub.docker.com/explore/

```bash |-- app | |-- controllers | |-- models | |-- views |-- docker | |-- nginx | |-- Dockerfile | |-- php | |-- Dockerfile | |-- mysql | |-- Dockerfile

2. Do it the docker way. Create a container for each purpose This means a container for the code, web server and persistence layer. 

- [Nginx](https://hub.docker.com/_/nginx/)
- [PHP](https://hub.docker.com/_/php/)
- [MySQL](https://hub.docker.com/_/mysql/)

3. Use [Docker Compose](https://docs.docker.com/compose/overview/). Starting the environment will be as easy as running: 

bash docker-compose up -d ```

  1. Iterate on docker containers as if you were iterating on code. Create a feature branch and merge only when its ready for use.

Continuous Integration

  1. Create a specific container to run the tests. For example, you can use a phpunit container. This encapsulates the testing environment in a single container. Thus any developer or machine can run the tests the same way.

  2. Automate tests. I prefer Shippable since it embraces docker, use your own machines and affordable. Theres many options out there so definitely choose one that works with you and your team.

Production

Once you've enabled containers for development and continuous integration, it will be time to release into production. The next step is to research the various docker schedulers and infrastructures.

Currently, I have chosen AWS ECS since it abstracts most of the cluster configuration. Its as easy as launching an AWS EC2 instance into the ECS cluster and configuring an ECS Service. The ECS service is defined by the task definition which is basically a json representation of the docker-compose file. Also, placing an AWS ELB in front of the ECS service provides managed load balancing and can enable rolling updates. Lastly, AWS Autoscaling will enable EC2 instance scaling and rotation in case a server goes down.

The important goal when shipping docker containers into production is immutability. During the development you will most likely mount your code into the container. In production, we want to build the container with the code and ship the immutable container. This will ensure the code's state. If there's an issue, the container can easily get pulled locally and debugged.

Continuous Delivery

The last step is to automate the delivery. This is pretty difficult and depends on infrastructure provider and scheduler, so I wont go into too much detail on this post.

I use Shippable + Terraform to deploy the AWS ECS service. I update the task definition file to point to the new artifact tag stored in AWS ECR. Then run Terraform apply to deploy the new ECS Service. This means once a pull request gets merged, shippable deliveries the code through automated terraform apply.

Summary

Containerizing the monolithic app enables quicker development cycles, automated continuous integration and deployment. These cycles didn't happen all at once. It started slowly but overtime Docker has enabled complete automation from development to production.