Docker + Ansible = Happiness!

A few months ago, I wrote a toy financial application in R language that scans NYSE and NASDAQ’s stocks, finds interesting patterns in a stock’s quote, generates a report, and sends it via email. It ran quite smoothly for a few months, but suddenly I became unsatisfied with how the infrastructure of the application was provisioned.

The dissatisfaction began when I heard about Docker.

Overview

Docker is a fantastic tool to containerize each process of an application. It allows you to create specialized containers that run a single process, and links together those containers to create the infrastructure of an application.

I decided to split the application in a few of Docker images:

  • A container based on busybox that holds the files produced by the application

  • madrossan/r-extended it’s the r-base image enhanced with useful R packages.

  • madrossan/tstock the application’s image that inherits from madrossan/r-extended and adds the application’s source file.

Unfortunately when developing this application, I found myself through several iterations of changing a Dockerfile of the images, rebuilding them, and deploying the application. It was painful to do manually, particularly because I have really little time to waste typing commands since I develop the application in my spare time.

To solve this automation problem I gave Fig a try because it looks promising and now it has officially joined Docker (with the name Compose), but I found out that it’s not exactly what I was looking for.

Get to know Ansible

I’ve always stared at configuration management systems like Chef or Puppet for a while, but I found them heavy since they are agent-based and with quite a steep learning curve.

Then I found Ansible. It’s a great agent-less tool to automate every aspect of an IT infrastructure in a simple way. The task of building the infrastructure and deploying the application are simply described by YAML files called “playbooks”.

Above, there’s my simple playbook. I don’t want to repeat paths in the application, in the Dockerfile and in the playbook, so for this specific case I decided to create the real application and Dockerfile from Jinja2 (the template engine used by Ansible) templates that are transformed in the actual files by the playbook’s execution. What I find amazing about Ansible is the plethora of modules in the “core” repository. My playbook uses Docker’s specific ones, a module to handle crontab entries, a module to render templates, and so on. You can also see that each task is described by a name that is really useful as documentation for anybody that reads or executes a playbook.

Among the several useful features of Ansible and additional tools, there is also Ansible Vault. It allows you to store data such as passwords and API keys in an encrypted file, so it’s safe to distribute the source code of an application without leaking data; have you ever heard about $5,000 Security Breach?

To create a new vault with the specified password and open the default editor:

$ ansible-vault create user-data.yml
Vault password:
Confirm Vault password:

A simple “cat” of the file reveals that it’s encrypted:

$ cat user-data.yml
$ANSIBLE_VAULT;1.1;AES256
64373132363633396261373538646633336136323638313638313262393232666361663032373138
6432326539353665373662396335333534396434396430620a393130323633653136663835633463
38316332353938363139343038333066303437666139336562333064643162313930326164346434
3165323536353964310a616365663565373737643264653961643535306262666630623132393032
65333033623666306237323864646362623363663031623932653836616665663436646231346466
3962333935336432393861626261363536353439323166613031

I use the great Mailgun REST service to send emails with the generated report and obviously Ansible Vault is a secure way to store my Mailgun’s API key!

Written on April 3, 2015