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.
1
ansible-galaxy init docker-role
And let’s create a playbook.yml, a destroy.yml and inventory.yml file as well
1
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.
├── 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.
1
2
3
4
5
6
7
8
9
10
11
12
---
# 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.
1
2
3
4
5
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.
1
2
3
4
5
6
7
8
9
10
11
12
13
---
- 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:
1
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:
1
2
#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.
1
2
3
4
5
6
---
- 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:
1
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