AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

Ansible Docker Compose: Manage Multi-Container Stacks (Guide)

By Luca Berton · Published 2024-01-01 · Category: installation

How to manage Docker Compose stacks with Ansible. Deploy, update, and manage multi-container applications with community.docker collection examples.

Ansible Docker Compose: Manage Multi-Container Stacks (Guide)

Managing Docker Compose with Ansible

Ansible and Docker Compose are a powerful combination. Ansible handles the infrastructure and deployment automation; Docker Compose manages multi-container applications. This guide shows you how to use them together.

See also: community.docker 5.1.0 — New Feature for Docker Compose Pull

Prerequisites

• Ansible 2.9+ on your control node • community.docker collection installed • Docker and Docker Compose on target hosts
# Install the Docker collection
ansible-galaxy collection install community.docker

Step 1: Install Docker with Ansible

---
- name: Install Docker
  hosts: docker_hosts
  become: true
  tasks:
    - name: Install prerequisites
      ansible.builtin.apt:
        name:
          - apt-transport-https
          - ca-certificates
          - curl
          - gnupg
          - lsb-release
        state: present
        update_cache: true

- name: Add Docker GPG key ansible.builtin.apt_key: url: https://download.docker.com/linux/ubuntu/gpg state: present

- name: Add Docker repository ansible.builtin.apt_repository: repo: "deb https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable" state: present

- name: Install Docker ansible.builtin.apt: name: - docker-ce - docker-ce-cli - containerd.io - docker-compose-plugin state: present

- name: Start and enable Docker ansible.builtin.service: name: docker state: started enabled: true

- name: Add user to docker group ansible.builtin.user: name: "{{ ansible_user }}" groups: docker append: true

See also: Ansible Docker: Complete Guide to Container Automation (2026)

Step 2: Deploy Docker Compose Files

Using the docker_compose_v2 Module

---
- name: Deploy application
  hosts: app_servers
  become: true
  tasks:
    - name: Create project directory
      ansible.builtin.file:
        path: /opt/myapp
        state: directory

- name: Copy docker-compose.yml ansible.builtin.copy: src: docker-compose.yml dest: /opt/myapp/docker-compose.yml

- name: Copy environment file ansible.builtin.template: src: .env.j2 dest: /opt/myapp/.env

- name: Deploy with Docker Compose community.docker.docker_compose_v2: project_src: /opt/myapp state: present register: output

- name: Show deployment output ansible.builtin.debug: var: output

Using Templates for docker-compose.yml

# templates/docker-compose.yml.j2
version: '3.8'
services:
  web:
    image: "{{ app_image }}:{{ app_version }}"
    ports:
      - "{{ app_port }}:80"
    environment:
      DATABASE_URL: "postgresql://{{ db_user }}:{{ db_password }}@db:5432/{{ db_name }}"
    depends_on:
      - db
    restart: always

db: image: postgres:16 volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_DB: "{{ db_name }}" POSTGRES_USER: "{{ db_user }}" POSTGRES_PASSWORD: "{{ db_password }}" restart: always

volumes: pgdata:

Step 3: Managing Containers

Start/Stop/Restart

- name: Stop application
  community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: absent

- name: Restart application community.docker.docker_compose_v2: project_src: /opt/myapp state: present recreate: always

Individual Container Management

- name: Run a single container
  community.docker.docker_container:
    name: redis
    image: redis:7-alpine
    ports:
      - "6379:6379"
    restart_policy: always
    state: started

Pull Latest Images

- name: Pull latest images
  community.docker.docker_compose_v2:
    project_src: /opt/myapp
    pull: always
    state: present
    recreate: always

See also: Ansible for Docker and Podman: Container Automation Complete Guide

Rolling Updates with Zero Downtime

---
- name: Zero-downtime deploy
  hosts: app_servers
  serial: 1
  become: true
  tasks:
    - name: Pull new image
      community.docker.docker_image:
        name: "myapp:{{ new_version }}"
        source: pull

- name: Update compose file ansible.builtin.template: src: docker-compose.yml.j2 dest: /opt/myapp/docker-compose.yml

- name: Recreate containers community.docker.docker_compose_v2: project_src: /opt/myapp state: present recreate: always

- name: Wait for health check ansible.builtin.uri: url: "http://localhost:{{ app_port }}/health" status_code: 200 register: health retries: 10 delay: 5 until: health.status == 200

Best Practices

Use templates for docker-compose.yml — inject environment-specific values Store secrets in Ansible Vault — never hardcode passwords Pin image versions — avoid latest tag in production Use health checks — verify services are healthy after deployment Manage volumes carefully — persistent data survives container recreation Use .env files via Ansible templates for Docker environment variables Serial deployments for zero-downtime rolling updates

FAQ

Which module should I use: docker_compose or docker_compose_v2?

Use docker_compose_v2 (for Docker Compose V2 CLI plugin). The older docker_compose module is deprecated.

Can Ansible build Docker images?

Yes, use community.docker.docker_image with build.path parameter to build from a Dockerfile.

How do I pass secrets to Docker containers via Ansible?

Use Ansible Vault to encrypt secrets, then pass them as environment variables in the docker-compose template.

Conclusion

Ansible + Docker Compose gives you reproducible, automated deployments for containerized applications. Use Ansible for the infrastructure layer and Docker Compose for application orchestration.

For more Docker and container tutorials, visit AnsiblePilot.

Deploy Docker Compose Stack

- name: Deploy app stack
  community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: present
  become: true

With Pull and Recreate

- community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: present
    pull: always
    recreate: always
  register: output

Stop Stack

- community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: absent

Deploy with Template

- name: Deploy docker-compose.yml
  ansible.builtin.template:
    src: docker-compose.yml.j2
    dest: /opt/myapp/docker-compose.yml
  become: true

- name: Start services community.docker.docker_compose_v2: project_src: /opt/myapp state: present pull: always become: true

{# templates/docker-compose.yml.j2 #}
services:
  web:
    image: nginx:{{ nginx_version }}
    ports:
      - "{{ http_port }}:80"
    volumes:
      - ./html:/usr/share/nginx/html:ro

app: image: myapp:{{ app_version }} environment: DATABASE_URL: "postgresql://{{ db_user }}:{{ db_pass }}@db:5432/{{ db_name }}" depends_on: - db

db: image: postgres:{{ postgres_version }} environment: POSTGRES_DB: "{{ db_name }}" POSTGRES_USER: "{{ db_user }}" POSTGRES_PASSWORD: "{{ db_pass }}" volumes: - db_data:/var/lib/postgresql/data

volumes: db_data:

Scale Services

- community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: present
    scale:
      web: 3
      worker: 2

Manage Specific Services

# Restart only the web service
- community.docker.docker_compose_v2:
    project_src: /opt/myapp
    services:
      - web
    state: restarted

Full Deployment Playbook

---
- name: Deploy application
  hosts: docker_hosts
  become: true
  vars:
    app_version: "2.5.0"
  tasks:
    - name: Create app directory
      file: { path: /opt/myapp, state: directory }

- name: Deploy compose file template: src: docker-compose.yml.j2 dest: /opt/myapp/docker-compose.yml

- name: Deploy env file template: src: .env.j2 dest: /opt/myapp/.env mode: '0600'

- name: Pull and deploy community.docker.docker_compose_v2: project_src: /opt/myapp pull: always state: present register: deploy

- name: Show deployment result debug: msg: "{{ deploy.actions | map(attribute='status') | list }}"

Key Parameters

| Parameter | Description | |-----------|-------------| | project_src | Path to docker-compose.yml | | state | present, absent, restarted | | pull | always, missing, never | | recreate | always, never, smart | | services | Target specific services | | scale | Scale service replicas | | profiles | Compose profiles |

FAQ

docker_compose vs docker_compose_v2?

docker_compose is for the old Python library (deprecated). docker_compose_v2 uses the Docker CLI plugin (docker compose). Always use v2.

How do I pass environment variables?

Use .env file in project directory, or environment: in docker-compose.yml. Template both with Ansible.

How do I view logs?

- command: docker compose -f /opt/myapp/docker-compose.yml logs --tail=50
  register: logs
- debug: var=logs.stdout_lines

Deploy Compose Stack

- community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: present
  become: true
  register: output

Pull and Recreate

- docker_compose_v2:
    project_src: /opt/myapp
    state: present
    pull: always
    recreate: smart  # Only recreate changed services
  become: true

Deploy with Template

# Generate docker-compose.yml from template
- template:
    src: docker-compose.yml.j2
    dest: /opt/myapp/docker-compose.yml
  become: true
  register: compose_file

# Deploy (only if config changed) - docker_compose_v2: project_src: /opt/myapp state: present become: true when: compose_file.changed

Compose Template Example

{# templates/docker-compose.yml.j2 #}
services:
  app:
    image: myorg/webapp:{{ app_version }}
    ports:
      - "{{ app_port }}:8080"
    environment:
      DB_HOST: postgres
      DB_PASSWORD: "{{ vault_db_password }}"
      REDIS_URL: redis://redis:6379
    depends_on:
      - postgres
      - redis
    restart: unless-stopped

postgres: image: postgres:{{ postgres_version | default('16') }} volumes: - pgdata:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: "{{ vault_db_password }}"

redis: image: redis:7-alpine volumes: - redis_data:/data

volumes: pgdata: redis_data:

Manage Specific Services

# Restart only the app service
- docker_compose_v2:
    project_src: /opt/myapp
    services: [app]
    state: restarted
  become: true

# Scale a service - docker_compose_v2: project_src: /opt/myapp services: [worker] scale: worker: 3 state: present become: true

Stop and Remove

# Stop all services
- docker_compose_v2:
    project_src: /opt/myapp
    state: stopped
  become: true

# Remove everything (containers + networks) - docker_compose_v2: project_src: /opt/myapp state: absent remove_volumes: true # Also remove volumes become: true

Full Deployment Playbook

- hosts: docker_hosts
  become: true
  vars:
    app_version: "2.5.0"
  tasks:
    - name: Create app directory
      file: { path: /opt/myapp, state: directory }

- name: Deploy compose file template: src: docker-compose.yml.j2 dest: /opt/myapp/docker-compose.yml register: compose_config

- name: Deploy environment file template: src: .env.j2 dest: /opt/myapp/.env mode: '0600' register: env_config

- name: Deploy stack docker_compose_v2: project_src: /opt/myapp pull: always state: present register: deploy

- name: Show deployed services debug: msg: "{{ deploy.services | default({}) }}"

Health Check After Deploy

- docker_compose_v2:
    project_src: /opt/myapp
    state: present
  become: true

- uri: url: "http://localhost:{{ app_port }}/health" status_code: 200 retries: 10 delay: 5 register: health until: health.status == 200

FAQ

docker_compose vs docker_compose_v2?

docker_compose is deprecated (uses docker-compose v1 Python library). Use docker_compose_v2 which uses the docker compose CLI (v2).

How to handle .env files?

Deploy .env with template module before running docker_compose_v2. Or pass environment variables in the compose template directly.

Can I use docker-compose.yml from a git repo?

- git: { repo: "{{ repo }}", dest: /opt/myapp, version: main }
- docker_compose_v2: { project_src: /opt/myapp }

Related Articles

the Ansible Galaxy referenceAnsible template vs copy moduleAnsible env var patternsthe Ansible Vault walkthroughthe Ansible Docker reference

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home