This is post serves as a reference to create a base for your next Docker project that might use your already in place ansible playbooks and roles.

Also sometimes setting up Docker to create fully configured containers based on extensive shell scripts and others at the Dockerfile level might become unmanagable. So just because Docker is awesome, and trendy these days, doesn’t mean you need to leave ansible getting dust.

tl;dr

Ansible is a great companion to Docker

The github url to the code presented here is available at the end of this post.

Ok, enough talk, ‘gimme the code’

Requirements

  • ansible
  • ansible-galaxy
  • Docker
  • Docker-py ( pip install docker-py )

Creating a ansible role to test docker

So first let’s make use of the ansible-galaxy to scaffold our role instead of creating all the files by hand.

    ansible-galaxy init docker-role

And let’s create a playbook.yml, a destroy.yml and inventory.yml file as well

touch playbook.yml destroy.yml inventory.yml

Ok so now we have our default ansible role directory and our created files

It should look like this

.
├── destroy.yml
├── docker-role
│   ├── defaults
│   │   └── main.yml
│   ├── files
│   ├── handlers
│   │   └── main.yml
│   ├── meta
│   │   └── main.yml
│   ├── README.md
│   ├── tasks
│   │   └── main.yml
│   ├── templates
│   ├── tests
│   │   ├── inventory
│   │   └── test.yml
│   └── vars
│       └── main.yml
├── inventory.yml
└── playbook.yml

So for now our role isn’t doing much, let’s add a few tasks to our docker-role/tasks/main.yml

Since we will be using an alpine based container let’s install a few apk packages in our main tasks file.

---
# main.yml
# tasks file for docker-role
- name: "Installing git using apk module"
  apk:
    name: git
    state: present

- name: "Installing Nano using apk module"
  apk:
    name: nano
    state: present

And that should do it, as the purpose of this post is to demonstrate how to use ansible to provision docker containers, without using ssh containers, but docker-cli (abstracted by ansible ) to interact with the containers.

Defining an ansible inventory with docker

So now let’s define our inventory.yml file with our yet to be created containers.

all:
  hosts:
    example-play:
      ansible_connection: docker
      ansible_python_interpreter: python

The important part of our inventory file, which could also have been defined as an ini file, is our vars regarding the connection to the host.

So the example-play will be name of our created container, and the variable ansible_connection: docker defines the driver that ansible will use to connect to the host.

Regarding the ansible_python_interpreter: python variable, was overriden from /usr/bin/python default value that ansible uses to refer to the python interpreter path, to python as we will be using the image python:alpine to create our container, and python is not available under the default path ansible searches.

Creating a playbook to create our docker container

So now that we have our docker compatible inventory file, let’s edit our playbook.yml file.

---
- name: Create our container
  hosts: localhost
  tasks:
    - docker_container:
        name: example-play
        image: python:alpine
        command: ["sleep", "1d"]

- name: Example play
  hosts: example-play
  roles:
    - name: "docker-role"

The first part of our playbook, creates the container based on the python:alpine image and sets our container to run the sleep 1d command on the run directive, so that the container doesn’t enter on the python interpreter when it goes up.

Ansible docker_container vars at https://docs.ansible.com/ansible/latest/modules/docker_container_module.html

The second part, targets our hosts defined at the example-play in our inventory.yml file, but this host is actually being created in the same playbook.

And finally will run our example role docker-role against that container.

So now we can run our playbook that we will create and run the role in it by running the following command:

ansible-playbook -i inventory.yml playbook.yml

Since ansible is all about idempotence, you may run the above command as many times as you wan’t and no changes should happen, meaning it won’t be creating the container more than once.

It will also name the container example-play when it creates it.

So if you want to enter your container at any time, you may run the docker cli command to interact directly with the container.

Example:

#The command below will run a python interpreter shell inside the container
docker exec -it example-play python

Destroying our inventory when done

Ok, so since we will be creating containers to be provisioned with ansible, it’s also a good idea to have a way to remove our docker inventory.

Let’s edit our destroy.yml with the following contents.

---
- hosts: localhost
  tasks:
    - docker_container:
        name: example-play
        state: absent

This is similar to our playbook.yml creation part, except for the state of the container we wish to have. The state absent is the same as stopped and removed.

To remove our container just run:

ansible-playbook destroy.yml

And that’s it for this post, thanks for reading, and hope you found it helpful.

Link to the github repository with the contents of this post:

https://github.com/Ilhicas/ansible-docker-example

André Ilhicas dos Santos

Devops Padawan, curious about systems automation, learning new languages, paradigms tools each day.

ilhicas ilhicas


Published