Docker virtualenv support

Python and Docker relationship

Docker can be expanded or managed by a few additional Python-based tools. The company behind Docker provides a docker-compose Python script which can be used to manage multiple Docker containers at a time. Ansible provides a few Docker-related modules as well. Therefore a correctly configured Python environment is very useful on a Docker host.

The debops.docker_server Ansible role maintains a separate Python virtualenv environment just for Docker-related Python packages. This is done so that Python modules used by upstream Docker, don't affect the host Python environment. The Docker virtualenv environment is by default located in the /usr/local/lib/docker/virtualenv/ directory but it can be changed if needed.

The docker-compose script will be symlinked in the host environment, in /usr/local/bin/docker-compose, so that the command can be used from the host's shell.

The Python interpreter located in the Docker virtualenv environment will be exposed in the host environment as /usr/local/bin/docker-python. That way you can use it in the Python scripts executed in the host environment. To use the Docker Python interpreter in a script, define it's shebang line as:

#!/usr/bin/env docker-python

Ansible modules and Docker virtualenv

The default host does not have any Docker-related Python modules available, therefore Ansible modules that interact with Docker, like docker, docker_container, docker_image, etc. will not work out of the box in normal Ansible playbooks and roles. To solve that, you can use the ansible_python_interpreter variable defined at the playbook level. Playbook variables cannot be templated by Jinja, therefore a static value must be used, and relates to the docker-python command exposed earlier.

Here's an example playbook that uses a Python interpreter from the Docker virtualenv environment:

---

- name: Set up a Redis Docker container
  collections: [ 'debops.debops' ]
  hosts: 'docker-host'
  become: True

  environment: '{{ inventory__environment | d({})
                   | combine(inventory__group_environment | d({}))
                   | combine(inventory__host_environment  | d({})) }}'

  vars:

    # Use Python from Docker virtualenv
    ansible_python_interpreter: '/usr/bin/env docker-python'

  tasks:

    - name: Manage redis container
      docker_container:
        name: 'local-redis'
        image: 'redis'
        published_ports: [ '127.0.0.1:6379:6379' ]
        restart_policy: 'always'
        state: 'started'

Keep in mind that more extensive playbooks that use Ansible roles or modules other than the Docker-related ones might need to be executed in their own separate plays, to use the host Python interpreter instead of the one maintained in the Docker virtualenv environment. Alternatively, you need to ensure that the Docker virtualenv environment contains all needed Python modules.

How to access the Docker virtualenv

To enter the Docker virtualenv environment on a host, execute the commands on the root account:

cd /usr/local/lib/docker/virtualenv
source bin/activate

After that you can execute usual pip commands to manage Python packages inside the environment.