As the release of Ansible 2.0 draws closer, I’d like to take a look at some of the new features that are coming down the pipe. In this post, we’ll look at the docker connection driver.

A “connection driver” is the mechanism by which Ansible connects to your target hosts. These days it uses ssh by default (which relies on the OpenSSH command line client for connectivity), and it also offers the Paramiko library as an alternative ssh implementation (this was in fact the default driver in earlier versions of Ansible). Alternative drivers offered by recent versions of ansible included the winrm driver, for accessing Windows hosts, the fireball driver, a (deprecated) driver that used 0mq for communication, and jail, a driver for connecting to FreeBSD jails.

Ansible 2.0 will offer a docker connection driver, which can be used to connect to Docker containers via the docker exec command. Assuming you have a running container named target, you can run an ad-hoc command like this:

$ ansible all -i target, -c docker -m command -a 'uptime'
target | SUCCESS | rc=0 >>
 03:54:21 up 7 days, 15:00,  0 users,  load average: 0.81, 0.60, 0.46

You can specify the connection driver as part of a play in your playbook:

- hosts: target
  connection: docker
  tasks:
    - package:
        name: git
        state: latest

Or as a variable in your inventory. Here’s an example that has both a docker container and an ssh-accessible host:

target ansible_connection=docker
server ansible_host=192.168.1.20 ansible_user=root

Given the following playbook:

- hosts: all
  tasks:
    - ping:

If we run it like this, assuming the above inventory is in the file inventory:

$ ansible-playbook -i inventory playbook.yml

The output will look something like:

TASK [ping] ********************************************************************
<192.168.1.20> ESTABLISH SSH CONNECTION FOR USER: root
<192.168.1.20> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s ... 192.168.1.20 ...
<192.168.1.20> PUT /tmp/tmpbtrmo5 TO /root/.ansible/tmp/ansible-tmp-1444795190.49-64658551273604/ping
<192.168.1.20> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s ... 192.168.1.20 ...
ESTABLISH DOCKER CONNECTION FOR USER: lars
<target> EXEC ['/usr/bin/docker', 'exec', '-i', u'target', '/bin/sh', '-c', ...
<target> PUT /tmp/tmpNmcPTf TO /root/.ansible/tmp/ansible-tmp-1444795190.53-251446545325875/ping
<192.168.1.20> ESTABLISH SSH CONNECTION FOR USER: root
<192.168.1.20> SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s ... 192.168.1.20 ...
ok: [server -> localhost] => {"changed": false, "ping": "pong"}
<target> EXEC ['/usr/bin/docker', 'exec', '-i', u'target', '/bin/sh', '-c', ...
ok: [target -> localhost] => {"changed": false, "ping": "pong"}

PLAY RECAP *********************************************************************
server                     : ok=2    changed=0    unreachable=0    failed=0   
target                     : ok=2    changed=0    unreachable=0    failed=0   

Now you have a unified mechanism for managing configuration changes in traditional hosts as well as in Docker containers.