Docker the Ansible Way — Part 2

Solution for Orchestrating Docker Containers with Ansible

Joaquín Menchaca (智裕)
3 min readMay 28, 2019

--

In the previous article, I presented the problem to how to orchestrate WordPress and MySQL 5.7 containers using Ansible. I also gave an example InSpec script that you can use to validate the solution, as you develop it.

In related articles, I showed how to do this in using a wrapper script (sh, python, ruby, perl) to automate Docker CLI (docker) command to solve this very same problem.

We should easily use the shell module to achieve the same effect with Ansible, but we would have to add an avalanche of when clauses to shield the tasks from errors and make them idempotent.

With Ansible, the docker modules, specifically docker_network, docker_volume, and docker_container, are now mature and stable, and interact with the underlying Docker Python SDK to allow us to do the same task, but with an flexible and intuitive Ansible YAML-DSL than Python code.

Below is the complete solution using Ansible, and a small code walkthrough.

Previous Article

Problem and Verification Script

Full Solution Source

You can download this and run it to see the results:

GIST=https://gist.githubusercontent.com/darkn3rd/93e0fa294baf2bc8bbe642d4a48188f7/raw/0e88da8a39781313fb8e6f9c28cb30d15511bcab/docker_run.ymlcurl -O $GIST
chmod +x docker_run.yml
./docker_run.yml

The Ansible playbook:

Code Walkthrough Notes

Here’s my explanation on the different parts of this script.

Variables

The first phase step in this framework is to set up variables that I would use throughout the playbook, and fetch the environment variable WORDPRESS_PORT.

In the variable blow, this line may draw your curiosity:

"{{ lookup('env','WORDPRESS_PORT') | default(8080)}}"

This is a Jinja2, which has is a template language used in Ansible. Ansible extends this language to add features that make it useful, or essential rather, for change configuration.

One of these features are the lookup plugins, including the env plugin, which we are using to fetch the environment.

Another feature are Jinja2 filters, which are useful for transforming data. We use a default filter, to set a value when existing value is not defined, which will happen if the environment variable that looked up does not exist.

Volume Task

We create our persistent volume with docker_volume:

- name: "Create a Volume"
docker_volume:
name: "{{ docker_volume }}"

Network Task

We create our private container network with docker_network:

- name: "Create a network"
docker_network:
name: "{{ docker_network }}"

Note that normally this operation was not idempotent in the past, but now this handles the scenario to only create one wordpress_net network, and doesn’t error out if it is created already.

MySQL Container Task

We launch our database container using mysql:5.7 image, use a restart policy of always, use our volume db_data, use our network of wordpress_net, and configure the database by passing environment variables to the container.

- name: "Launch database container"
docker_container:
name: "{{ db_name }}"
image: mysql:5.7
volumes:
- "{{ docker_volume }}:/var/lib/mysql:rw"
restart_policy: always
network_mode: "{{ docker_network }}"
env:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress

If this db container is already running, stopped, or removed, Ansible will handle bringing the container to the desired state specified above.

WordPress Container Task

We launch our web application WordPress container using the image wordpress:latest, use a restart policy always, use our network of wordpress_net, map the container port of 80 to a host port we can access on our workstation, and configure WordPress app by passing environment variables to the container.

- name: "Launch wordpress container"
docker_container:
name: "{{ wp_name }}"
image: wordpress:latest
ports:
- "{{ wp_host_port }}:{{ wp_container_port }}"
restart_policy: always
network_mode: "{{ docker_network }}"
env:
WORDPRESS_DB_HOST: "{{ db_name }}:3306"
WORDPRESS_DB_PASSWORD: wordpress

If this wordpress container is already running, stopped, or removed, Ansible will handle bringing the container to the desired state specified above.

Final Notes

This was tested on both Ansible 2.7 and Ansible 2.8, and should work for Ansible 2.2 and above. I hope this was useful for both understanding Docker and Ansible, as well as using InSpec if you used that to verify the results.

--

--

Joaquín Menchaca (智裕)
Joaquín Menchaca (智裕)

Written by Joaquín Menchaca (智裕)

DevOps/SRE/PlatformEng — k8s, o11y, vault, terraform, ansible

No responses yet