Image for post
Image for post

Docker: Using Shell or Ansible

Comparison of Docker Commands and Ansible Docker Module

Docker is a great tool to pull down pre-packaged images of services to run on your system. This is a small tutorial that shows how to quickly run a WordPress application using either shell commands with the docker tool, or using Ansible tool that uses DSL in a YAML file to do the same thing.

Prerequisites

You will need the following tools for this tutorial:

Docker runs natively on Linux, so installation is rather straight forward process for popular distributions:

On macOS, you will need to run a virtual guest that will host the docker service. For the virtual guest, you can either use Docker Machine, which uses Virtualbox by default, or you can use Docker-for-Mac, which uses HyperKit (based on xhyve). You can actually install both of these tools, and decide, which one to use.

You can get Docker Machine by installing Docker Toolbox:

For Docker-for-Mac, you can get this from here:

After installing and enabling Docker for your current user, you can get Ansible and Docker python library if Python and Pip are installed:

pip install ansible
pip install docker

Overview

This small tutorial will create the following components in Docker:

  • Docker Network: all containers will run on this network and be able to communicate to each other.
  • Docker Volume: a reusable volume on the host to store database data
  • MySQL container with database saved local volume
  • WordPress container linked to MySQL database

Part I: The Shell Way with Docker Command

This is a walkthrough step-by-step to use docker command line tool to create a small infrastructure (network and persistence volume) along with containers using these resources.

We’ll need to create a network so that all containers we wish to use can communicate to each other.

docker network create "wordpress_net"

This command unfortunately is not idempotent, so the command will return an error if the network already exists. If you want to use this in automation, you need to skip creating the network if it already exists:

docker network list | grep -q "wordpress_net" || \
docker network create "wordpress_net"

Normally, when you remove containers, all the data on the volumes will be lost. To preserve the data, we create a reusable volume on the host.

docker volume create -d local --name "db_data"

Now we need to download and run a MySQL container. We can run this using this command, and reference our reusable volume, which is mounted at /var/lib/mysql inside the container.

We put run this container on the network wordpress_net and give it the name db, so that WordPress application can communicate to it by that name.

docker run -d \
-v db_data:/var/lib/mysql:rw \
--network='wordpress_net' \
--network-alias db \
--restart=always \
-e MYSQL_ROOT_PASSWORD='wordpress' \
-e MYSQL_PASSWORD='wordpress' \
-e MYSQL_USER='wordpress' \
-e MYSQL_DATABASE='wordpress' \
--name db mysql:5.7

For the MySQL database itself, we can configure initial accounts by passing in environment variables. This will setup a root password, a user account, as well as a database.

Now that the database is up and running, we can bring up the application. We tell WordPress what to use for the database as well as the password to use. By default, the user that WordPress uses is wordpress, unless we specify otherwise.

# start wordpress application
docker run -d \
--network=wordpress_net \
--network-alias wordpress \
-p "8080:80" \
--restart=always \
-e WORDPRESS_DB_HOST="db:3306" \
-e WORDPRESS_DB_PASSWORD='wordpress' \
--name wordpress wordpress:latest

We can try out the solution by pointing your browser to http://localhost:8080 if you run Docker natively or use Docker-for-Mac.

If you are using Docker Machine, then use docker machine ip to get the IP address, and navigate to that IP address at port 8080.

Part II: The Ansible Way

Ansible is utilized here as an orchestration tool to automate Docker. Here we will create a playbook that will do the same thing that we did before with the docker command, except instead of a long command, we’ll have descriptive key-value pairs.

Create a file called docker_wordpress.yml. We’ll fill it out with the basic structure and fill in the vars and tasks later as we go.

---
- hosts: localhost
gather_facts: no
vars:
# variables go here
tasks:
# tasks go here

These will be the variables we’ll use through the rest of the playbook:

  vars:
docker_volume: db_data
docker_network: ansible_net
db_name: db
wp_name: wordpress
wp_host_port: 8000
wp_container_port: 80

These are similar to what we used from the command line before, except that we are using port 8000 this time and a different docker network, called ansible_net.

We can create a volume docker resource using the docker_volume (requires Ansible 2.4 or higher).

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

The docker_network (Ansible 2.2 or higher) can create a network and shield us from any Docker errors, should the network already exist.

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

Let’s define how to run the MySQL container.

    - name: "Launch database container"
docker_container:
name: "{{ db_name }}"
image: mysql:5.7
volumes:
- "{{ docker_volume }}:/var/lib/mysql:rw"
restart: true
networks:
- name: "{{ docker_network }}"
alias:
- "{{ db_name }}"
env:
MYSQL_ROOT_PASSWORD: wordpress
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress

Let’s define how to run WordPress container.

    - name: "Launch wordpress container"
docker_container:
name: "{{ wp_name }}"
image: wordpress:latest
ports:
- "{{ wp_host_port }}:{{ wp_container_port }}"
restart: true
networks:
- name: "{{ docker_network }}"
alias:
- "{{ wp_name }}"
env:
WORDPRESS_DB_HOST: "{{ db_name }}:3306"
WORDPRESS_DB_PASSWORD: wordpress

The final Ansible playbook when put together will look like the following below:

Running the Playbook

With Ansible and the python docker library installed on the host, you can bring up WordPress by running:

ansible-playbook docker-wordpress.yml

Make sure you docker is running, and you have can run containers before doing this, such as docker run hello-world.

We can try out the solution by pointing your browser to http://localhost:8000 if you run Docker natively or use Docker-for-Mac.

If you are using Docker Machine, then use docker machine ip to get the IP address, and navigate to that IP address at port 8000.

Final Thoughts

Docker is a great tool for quickly testing applications and services without the need to spend a lot of time to configure these locally. We did a comparison of both the vanilla docker command and some of the rich modules available in Ansible that can be used to automate and orchestrate Docker.

The docker command is common for regular day-to-day usage of Docker and for creating build and test scripts, should you use Docker containers in a Continuous Integration build environment.

For deployment scenarios, where you need to deploy docker containers, Ansible has been a very popular tool for this, and may be useful to get started with deploying services using Docker and experimenting with Immutable Production patterns before moving to more robust orchestration solutions like Kubernetes.

Written by

Linux NinjaPants Automation Engineering Mutant — exploring DevOps, Kubernetes, CNI, IAC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store