Ansible - How to use a docker connection with docker-machine

Oscar Brito

Docker is very cool to create lightweight hosts to your micro/macro services in a repeatable way.

The problem with using docker is that the machine configuration is not decoupled from docker itself, so you will be stuck with docker to setup your infrastructure.

How cool it would be to use ansible and docker together in order to:

  1. isolate machine configuration
  2. use docker and easily replicate environments

This article will show you how to create an empty centos 7 docker container within docker-machine and use ansible to do the machine setup.

By doing this you can use share machine configuration tasks between projects, keeping your entire infrastructure updated. Imagine that!

A ready to run example is available at example-ansible-docker-connection.

dynamic inventory

Because docker runs on top of a linux kernel, a docker-machine virtual machine is used to host docker on OSX and Windows machines.

This configuration is transparent to the docker client, after an eval "$(docker-machine env local)", which sets up some connection environment variables that the docker client needs.

We'll need this docker-machine information on our ansible playbooks in order to call docker. This is done using a dynamic inventory which, in this case, is a python script that evaluates our current environment variables.

playbook

Now that we have the docker host information we can write an ansible playbook to startup a docker and use ansible to install some packages within the newly created docker container.

---

# run an empty centos 7 container
- hosts: docker-host

  vars:
    # workaround error "docker-py is needed for this module"
    ansible_python_interpreter: "/usr/bin/env python"

  tasks:

    - name: build docker image
      docker:
        image: "centos:7"
        name: "divhide-test"
        state: "reloaded"
        docker_url: "{{ docker_host_url }}"
        use_tls: "encrypt"
        command: sleep 5m
      environment:
        DOCKER_CERT_PATH: "{{ docker_host_cert_path }}"
      # register the running container
      register: docker_result

    - name: add new docker connection {{ docker_result.ansible_facts.docker_containers[0].Config.Hostname }} to docker-container inventory group
      add_host:
        name: "{{ docker_result.ansible_facts.docker_containers[0].Config.Hostname }}"
        groups: "docker-container"
        ansible_connection: docker
        ansible_ssh_user: "root"
        ansible_become_user: "root"
        ansible_become: "yes"


# setup the new machine using ansible instead of docker
- hosts: docker-container
  tasks:

    - name: install vi
      yum:
        name: vi
        state: present

Note that this playbook is dynamically adding a new host to the docker-container group using a docker connection instead of using SSH.

how to run

Let's get busy then. To run this example you simply have to do the following.

# download the example
git clone https://github.com/divhide/example-ansible-docker-connection.git

# start your docker-machine virtual machine
docker-machine start local  
eval "$(docker-machine env local)"

# run the playbook using the dynamic inventory
ansible-playbook -i docker-machine.py playbook.yml

We have now a docker container running and configured with ansible.

summary

This is just a simple example of a machine configuration playbook that can be easily changed to point to another type of hosting other than docker.

Downsides? Problems? Share your thoughts by commenting.

Oscar out