I recently had the opportunity to test out Ansible’s ability to interact with docker containers. Some might ask why we would want Ansible to connect to running containers. Afterall, we can build the containers to our liking using ansible-container, or even mundane tools such as Docker’s Dockerfile. Also, we can link configuration files at runtime to override the container’s settings where appropriate.
The point, though, is to leverage Ansible’s capability as an orchestration tool.
As a very basic example, assume that you have plays for your non-docker environment to ensure MySQL users exist. How do you do that with Docker containers?
You have a few options:
- Assume you have users with appropriate privileges that can connect remotely, you can execute the Ansible plays locally to connect to MySQL over the Docker network. You might need a few tweaks to the playbooks to connect remotely instead of locally and add module dependencies to your Ansible control machine.
- You might subscribe to the idea of running basic services such as SSH on your Docker containers, so Ansible would be able to connect just the same.
- If you run Ansible 2.0+, you can leverage Ansible’s docker connection driver, adding to the list of existing drivers such as SSH, winrm, and paramiko.
Using the Docker connection driver
In any event, my test images do not have SSH. I try to keep them as slim as possible, or use upstream images such as the officially supported MySQL Docker image.
And they do not allow remote login to users with ability to create users and grant privileges.
Using the Docker connection driver leverages `docker exec` to connect to Docker containers. To connect to my container, it should be just as simple as specifying the connection driver to be docker with `-c docker`.
Unfortunately, this resulted in the following unhelpful error:
$ ansible --version ansible 126.96.36.199 $ ansible all -i mysqla, -c docker -m command -a 'uptime' mysqla | FAILED | rc=0 >> MODULE FAILURE
Verbose logging was not very helpful either:
$ ansible all -i mysqla, -c docker -m command -a 'uptime' -vvvv Loaded callback minimal of type stdout, v2.0 <mysqla> ESTABLISH DOCKER CONNECTION FOR USER: root <mysqla> EXEC ['/usr/local/bin/docker', 'exec', '-i', 'mysqla', ...] <mysqla> PUT ... TO ... <mysqla> EXEC ['/usr/local/bin/docker', 'exec', '-i', 'mysqla', ...] mysqla | FAILED | rc=0 >> MODULE FAILURE
Remember the Dependencies!
The answer comes from remembering which dependencies are necessary for Ansible to manage remote hosts: primarily Python. Installing Python on my container results in a successful execution:
root@8425c734000a:/# apt update && apt-get install -y python $ ansible all -i mysqla, -c docker -m command -a 'uptime' mysqla | SUCCESS | rc=0 >> 19:25:49 up 9 days, 1:48, 0 users, load average: 0.01, 0.05, 0.02
Ansible enables you to orchestrate your Docker containers starting with Ansible 2.0 using the new docker connection driver. This is very useful if you keep your containers slim and don’t run services such as SSH.
But regardless of the connection method, if you do keep your containers slim, it is very possible you do not have the basic Ansible dependencies installed. The dependencies are primarily python and any module-specific dependencies required to manage those containers, such as python-mysqldb.
Be sure to install them if you want your Ansible plays to be able to execute successfully against your Docker containers. Happy orchestrating!