Setting up an automated local development environment using Docker and Vagrant
Problem Statement
We need a way to build isolated and repeatable production like development environments on local machine.
Possible Solutions
Classic VMs ensure isolated and repeatable environments. But these are resource consuming. Developers need to code/build/test every few minutes and won’t accept the virtualization overhead. So instead of make OS level containers (i.e., VMs), using application level containers is extremely fast and easier to maintain. For this we use docker application containers and vagrant automation to provide the desired OS for docker container to run in isolation -
Feature | Options |
---|---|
Application Container | Docker |
Base OS Provider | Vagrant |
Solution Evaluations
NOTE: Image Source docker-dev-in-box-environment
In this experiment, we write code for setting up the base infrastructure on local developer machine, a.k.a., Infrastructure as code (IaC). The project on which this experiment is done - github.com/airavata-courses/spring17-API-Server - a microservice. For building Infrastructure as code the additional files created are “Dockerfile” for each microservice, and one “Vagrantfile” as provider automation script. For any project this is a one time effort. After that building production like environment on local machine is fast and easy. So it can save a lot time and effort compared to doing the same activity manually.
Docker
Dockerfiles are really straightforward and there is an excellent online reference manual. You can directly run a docker container from the command like this -
docker build -t=myDockerImageName .
And you can run a docker-image as container like this -
docker run -a stdin -a stdout -i -t myDockerImageName /bin/bash
NOTE: Image Source running-docker-directly
By default, on Windows or Mac machine, these containers run on top of boot2docker docker-machine by docker installation. On linux, docker directly leverages the virtualization from the host machine kernel. The docker container (i.e., running images) consumes few MBs of memories as compared to running a VM which consumes memory in GBs. On Windows or Mac machine, in order to run docker-containers, on custom linux flavor, Vagrant VM automation tool is useful which is explained below.
Vagrant
Vagrant is just a Docker wrapper on systems that support Docker natively while it spins up a host VM to run containers on systems that don’t support it. Users don’t have to bother whether Docker is supported natively or not : the same configuration will work on every OS. Vagrant can orchestrate Docker containers: run multiple containers concurrently and link them together. Docker hosts are not limited to boot2docker (a Virtualbox image of Tiny Core Linux) but Debian, Ubuntu, CoreOS and other Linux distros are supported too. And can run on more stable VM managers than Virtualbox (e.g. VMWare).
NOTE: Image Source docker-provider-for-vagrant
The basic usage of vagrant with docker as the provider, brings the same situation (see above). That is, on platforms that don’t support containers, by default Vagrant spins up a Tiny Core Linux (boot2docker) Docker host.
If our production environment is running some other linux (say ubuntu 14.04 LTS) we have a gap between the configurations of development and production environments. In some cases, this can virtually be the cause of a production bug, impossible to identify in development environment.
NOTE: Image Source docker-provider-for-vagrant
So, one of Vagrant main conveniences is that it let us specify a custom Docker host and we are not stuck with boot2docker VM (see above). For this the main Vagrantfile
references to another vagrantfile (say DockerHostVagrantfile
) like this -
...
# other "docker provider" specific configuration
...
d.vagrant_vagrantfile = "./DockerHostVagrantfile"
Where DockerHostVagrantfile will override the docker-provider specific default configurations. And you replace boot2docker with production environment VM (say ubuntu 14.04 LTS). Using Vagrant to control Docker containers can be useful if dealing with a mix of different platforms: some Docker-enabled and others not. In this scenario using Vagrant makes the process of setting up an environment consistent across different platforms.
Conclusion
Writing Dockerfile and Vagrantfile requires initial effort. But the over all gains are considerable for long term. Infrastructure as Code provides the fastest and most resource-effective way of building isolated and repeatable environments. Since containers are isolated instances that run your applications. These lightweight instances can be replaced, rebuilt, and moved around easily. This allows us to mirror the production and development environment and is a tremendous help in the continuous integration and delivery process.