Ansible's Docker Compose Problem
2021-12-02
Background Info
Over the last year I’ve been working more with ansible, I’ve even used IronicBadger’s Infra playbook as a base to my own personal infrastructure playbook.
However one problem that has come up recently was with the release of docker-compose 2.0 because it was rewritten in go.
Don’t get me wrong, so far the go version of docker-compose has been fantastic, it appears to be faster to run and I love the changes they have done to the terminal output.
However due to the change from python to go, docker-compose no longer works in ansible
The Problem as it stands
Currently because the Ansible module imports the docker-compose python code directly it is incompatible with docker-compose releases 2.0.0 or later.
There is an issue raised on github to solve this, however the problem is that someone needs to write a python module that will interact with docker-compose via the cli.
Understandably no-one has yet to tackle this since it would be quite the undertaking to get this to work and be 100% compatible.
Unfortunately for me, a good 80-90% of my ansible roles I’ve written for my private infrastructure rely on docker compose.
So I was faced with two ways forward:
- Rewriting everything to be under the docker network and docker run modules, or
- Find a way to get docker-compose’s python module reinstalled at the same time as the latest docker compose release.
Option 1 I wasn’t looking forward to since I would be basically doing what docker-compose does in one ansible play step myself over multiple ansible steps. But Option 2 could lead to broken python installs if I am not careful.
However recently I was reminded of a fantastic feature/module of python, virtual environments
The workaround: virtualenv
Virtual Python Environments, the perfect way of installing python modules via pip in a safe way.
For the uninitiated, virtual environments, or venvs are a python substructure that allows you to manage your own user-managed python install independent of the system’s installed python modules. Very useful if you want to use pip for installing python modules, but also don’t want to cross-contaminate your system with pip managed modules. Many package managers will complain about finding files not owned by a package when attempting to install said module system wide.
The remaining question is how easy can Ansible be setup to use it?
After some searching, it is indeed quite easy, thanks to the work Matt Schlobohm showed in this stack overflow question
And after some testing with the ansible_python_interpreter variable, I got it working with minor tweaking.
Here are the relevant files I have in the role that sets up the virtual environment on my Arch/Manjaro boxes
./roles/python_venv_setup/tasks/main.yml
- name: Ensure dependencies are installed
community.general.pacman:
name:
- docker
- docker-compose
- python-docker
- python-pip
- python-pyaml
- python-setuptools
- python-yaml
- python-virtualenv
state: present
update_cache: true
- name: Setup Python virtualenv
ansible.builtin.pip:
virtualenv: '/var/local/docker-appdata/.venv/'
state: present
name:
- docker
- docker-compose
- PyYAML
- pyaml
- name: Copy pyvenv file
ansible.builtin.copy:
src: pyvenv
dest: '/var/local/docker-appdata/.venv/bin/pyvenv'
owner: root
group: root
mode: '775'
./roles/python_venv_setup/files/pyvenv
#!/bin/bash
source "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )/activate"
python $@
Main Playbook YAML file
- hosts: all
vars:
ansible_python_interpreter: /usr/bin/python3
roles:
- python_venv_setup
- hosts: all
roles:
- docker_compose_project_1
- docker_compose_project_2
- docker_compose_project_3
Finally in the inventory file, you set ansible_python_interpreter to the location of the pyvenv file,
In the example above, that would be /var/local/docker-appdata/.venv/bin/pyvenv
What all of this does is first run through the python dependencies and ensures everything is there for it to work, then through the ansible builtin module pip it sets up the virtualenv and installs docker-compose inside of it.
Finally the pyvenv file auto sources & activates the virtualenv’s python and passes all python calls to the virtualenv’s version of python.
With this it has all of the tools needed to get docker-compose working again while keeping the up to date copy of docker-compose installed.
One note for Python
Any remote python modules that are required now need to be installed into the virtualenv, in my case I have both PyYAML and pyaml because some of the modules I use need both.