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: Complete Guide to Container Automation (2026)

By Luca Berton · Published 2026-04-03 · Category: installation

Complete guide to automating Docker with Ansible. Manage containers, images, networks, volumes, and docker-compose with community.docker collection.

Ansible's community.docker collection provides modules to manage Docker containers, images, networks, and Docker Compose deployments — all from your playbooks.

Prerequisites

# Install the collection
ansible-galaxy collection install community.docker

# Python requirements on managed hosts pip install docker

See also: Ansible docker_container Module: Manage Docker Containers (Guide)

Manage Containers

Start a container

- name: Run nginx container
  community.docker.docker_container:
    name: webserver
    image: nginx:latest
    state: started
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /opt/nginx/html:/usr/share/nginx/html:ro
      - /opt/nginx/conf:/etc/nginx/conf.d:ro
    restart_policy: unless-stopped

Container with environment variables

- name: Run PostgreSQL
  community.docker.docker_container:
    name: postgres
    image: postgres:16
    state: started
    ports:
      - "5432:5432"
    env:
      POSTGRES_PASSWORD: "{{ vault_db_password }}"
      POSTGRES_DB: myapp
      POSTGRES_USER: appuser
    volumes:
      - pgdata:/var/lib/postgresql/data

Stop and remove containers

- name: Stop container
  community.docker.docker_container:
    name: webserver
    state: stopped

- name: Remove container community.docker.docker_container: name: webserver state: absent

Manage Images

- name: Pull latest image
  community.docker.docker_image:
    name: nginx
    tag: latest
    source: pull

- name: Build image from Dockerfile community.docker.docker_image: name: myapp tag: "{{ app_version }}" build: path: /opt/myapp dockerfile: Dockerfile source: build

- name: Remove old images community.docker.docker_image: name: myapp tag: old-version state: absent

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

Docker Networks

- name: Create app network
  community.docker.docker_network:
    name: app_network
    driver: bridge
    ipam_config:
      - subnet: 172.20.0.0/16

- name: Run container on custom network community.docker.docker_container: name: myapp image: myapp:latest networks: - name: app_network ipv4_address: 172.20.0.10

Docker Volumes

- name: Create named volume
  community.docker.docker_volume:
    name: app_data
    driver: local

- name: Use volume in container community.docker.docker_container: name: myapp image: myapp:latest volumes: - app_data:/data

See also: Ansible Execution Environments: Build Custom EEs for Enterprise Automation

Docker Compose

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

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

Generate docker-compose.yml with Ansible

- name: Create docker-compose.yml
  ansible.builtin.copy:
    content: |
      version: '3.8'
      services:
        web:
          image: nginx:latest
          ports:
            - "{{ http_port }}:80"
          volumes:
            - ./html:/usr/share/nginx/html
          restart: unless-stopped
        db:
          image: postgres:16
          environment:
            POSTGRES_PASSWORD: {{ vault_db_pass }}
          volumes:
            - pgdata:/var/lib/postgresql/data
          restart: unless-stopped
      volumes:
        pgdata:
    dest: /opt/myapp/docker-compose.yml
  notify: restart compose

handlers: - name: restart compose community.docker.docker_compose_v2: project_src: /opt/myapp state: present recreate: always

Install Docker with Ansible

- name: Install Docker on Ubuntu
  hosts: all
  become: true
  tasks:
    - name: Install prerequisites
      ansible.builtin.apt:
        name:
          - ca-certificates
          - curl
          - gnupg
        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 Docker service ansible.builtin.service: name: docker state: started enabled: true

Container Health Checks

- name: Run container with health check
  community.docker.docker_container:
    name: myapp
    image: myapp:latest
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

FAQ

Can I manage remote Docker hosts?

Yes. Set docker_host: "tcp://remote:2376" or use DOCKER_HOST environment variable. For TLS, configure tls, tls_verify, and certificate paths.

How do I update a running container?

Pull the new image, then recreate: set recreate: true or image: myapp:{{ new_version }}. The module handles stop → remove → start.

Docker Compose v1 vs v2 in Ansible?

Use community.docker.docker_compose_v2 for Docker Compose v2 (plugin). The older docker_compose module targets Compose v1 (standalone binary, deprecated).

Install Docker with Ansible

- name: Install Docker on Ubuntu
  hosts: all
  become: true
  tasks:
    - ansible.builtin.apt:
        name: [docker.io, docker-compose-v2, python3-docker]
        state: present
        update_cache: true

- ansible.builtin.service: name: docker state: started enabled: true

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

Run Containers

- name: Run nginx container
  community.docker.docker_container:
    name: web
    image: nginx:latest
    state: started
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /opt/website:/usr/share/nginx/html:ro
      - /opt/nginx.conf:/etc/nginx/nginx.conf:ro
    restart_policy: unless-stopped
    env:
      NGINX_HOST: example.com

Docker Compose

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

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

Manage Images

# Pull image
- community.docker.docker_image:
    name: python
    tag: "3.12-slim"
    source: pull

# Build from Dockerfile - community.docker.docker_image: name: myapp tag: latest source: build build: path: /opt/myapp dockerfile: Dockerfile

# Remove old images - community.docker.docker_prune: images: true images_filters: dangling: true

Networks

- community.docker.docker_network:
    name: app-network
    driver: bridge
    ipam_config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

- community.docker.docker_container: name: app image: myapp:latest networks: - name: app-network ipv4_address: 172.20.0.10

Volumes

- community.docker.docker_volume:
    name: db-data
    driver: local

- community.docker.docker_container: name: postgres image: postgres:16 volumes: - db-data:/var/lib/postgresql/data env: POSTGRES_PASSWORD: "{{ vault_db_pass }}"

Full Stack Example

---
- name: Deploy app stack
  hosts: docker_hosts
  become: true
  tasks:
    - community.docker.docker_network:
        name: appnet

- community.docker.docker_container: name: db image: postgres:16 networks: [{ name: appnet }] volumes: ["dbdata:/var/lib/postgresql/data"] env: POSTGRES_DB: myapp POSTGRES_PASSWORD: "{{ vault_db_pass }}"

- community.docker.docker_container: name: redis image: redis:7-alpine networks: [{ name: appnet }]

- community.docker.docker_container: name: app image: "myapp:{{ app_version }}" networks: [{ name: appnet }] ports: ["8080:8080"] env: DATABASE_URL: "postgresql://postgres:{{ vault_db_pass }}@db:5432/myapp" REDIS_URL: "redis://redis:6379" restart_policy: unless-stopped

Key Modules

| Module | Purpose | |--------|---------| | docker_container | Run/manage containers | | docker_image | Pull/build images | | docker_compose_v2 | Docker Compose | | docker_network | Networks | | docker_volume | Volumes | | docker_prune | Cleanup | | docker_login | Registry auth |

FAQ

Do I need Python Docker SDK?

Yes — install python3-docker on managed hosts. Or: pip install docker

How do I update a running container?

Set pull: true and recreate: true (or use comparisons for smart recreation):

- community.docker.docker_container:
    name: app
    image: myapp:latest
    pull: true
    recreate: true

Ansible vs Docker Compose directly?

Ansible adds inventory management, secrets (Vault), multi-host orchestration, and integration with non-Docker infrastructure. Use Ansible when Docker is part of a larger automation workflow.

Install Collection

ansible-galaxy collection install community.docker

Run a Container

- community.docker.docker_container:
    name: nginx
    image: nginx:latest
    state: started
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /opt/nginx/html:/usr/share/nginx/html:ro
      - /opt/nginx/conf:/etc/nginx/conf.d:ro
  become: true

Container with Environment Variables

- docker_container:
    name: myapp
    image: myorg/myapp:{{ version }}
    state: started
    env:
      DB_HOST: "db.internal"
      DB_PORT: "5432"
      REDIS_URL: "redis://cache:6379"
      APP_ENV: "production"
    restart_policy: unless-stopped

Docker Compose

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

# Or pull and recreate - docker_compose_v2: project_src: /opt/myapp state: present pull: always recreate: smart

Manage Images

# Pull image
- community.docker.docker_image:
    name: nginx
    tag: "1.25"
    source: pull

# Build image - docker_image: name: myorg/myapp tag: "{{ version }}" source: build build: path: /opt/myapp dockerfile: Dockerfile

Manage Networks

- community.docker.docker_network:
    name: myapp_network
    driver: bridge
    ipam_config:
      - subnet: 172.20.0.0/16
        gateway: 172.20.0.1

- docker_container: name: myapp image: myorg/myapp networks: - name: myapp_network ipv4_address: 172.20.0.10

Manage Volumes

- community.docker.docker_volume:
    name: myapp_data

- docker_container: name: postgres image: postgres:16 volumes: - myapp_data:/var/lib/postgresql/data env: POSTGRES_PASSWORD: "{{ vault_db_password }}"

Container Health Check

- docker_container:
    name: myapp
    image: myorg/myapp
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 30s

Full Stack Example

- name: Deploy application stack
  hosts: docker_hosts
  become: true
  vars:
    app_version: "2.5.0"
  tasks:
    - docker_network:
        name: app_net

- docker_container: name: postgres image: postgres:16 networks: [{ name: app_net }] volumes: [pgdata:/var/lib/postgresql/data] env: POSTGRES_PASSWORD: "{{ vault_db_pass }}"

- docker_container: name: redis image: redis:7-alpine networks: [{ name: app_net }]

- docker_container: name: webapp image: "myorg/webapp:{{ app_version }}" networks: [{ name: app_net }] ports: ["80:8080"] env: DATABASE_URL: "postgresql://postgres:{{ vault_db_pass }}@postgres/app" REDIS_URL: "redis://redis:6379" restart_policy: unless-stopped

Cleanup

# Remove stopped containers
- docker_container:
    name: old-app
    state: absent

# Prune unused images - community.docker.docker_prune: images: true containers: true volumes: false # Be careful with data volumes

FAQ

docker_container vs docker_compose?

docker_container manages individual containers. docker_compose_v2 manages multi-container stacks from docker-compose.yml. Use compose for complex stacks.

Do I need Docker installed first?

Yes — install Docker on the target host first. Use geerlingguy.docker role or install manually.

How to handle secrets?

Use Ansible Vault for environment variables. Never put secrets in Dockerfiles or images.

Install Collection

ansible-galaxy collection install community.docker
pip install docker  # Python SDK required

Run a Container

- community.docker.docker_container:
    name: nginx
    image: nginx:latest
    state: started
    ports:
      - "80:80"
      - "443:443"
    restart_policy: unless-stopped

Container with Volumes

- docker_container:
    name: myapp
    image: myorg/myapp:v2
    volumes:
      - /opt/data:/app/data
      - /opt/config:/app/config:ro
    env:
      DATABASE_URL: "postgresql://db:5432/myapp"
      APP_SECRET: "{{ vault_app_secret }}"

Pull Image

- community.docker.docker_image:
    name: myorg/myapp
    tag: "{{ app_version }}"
    source: pull

Build Image

- docker_image:
    name: myorg/myapp
    tag: "{{ app_version }}"
    source: build
    build:
      path: /opt/myapp
      dockerfile: Dockerfile

Docker Network

- community.docker.docker_network:
    name: app_network
    driver: bridge

- docker_container: name: myapp image: myorg/myapp:latest networks: - name: app_network

Docker Volume

- community.docker.docker_volume:
    name: db_data
    state: present

- docker_container: name: postgres image: postgres:16 volumes: - db_data:/var/lib/postgresql/data env: POSTGRES_PASSWORD: "{{ vault_db_pass }}"

Docker Compose

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

Cleanup

# Remove stopped containers
- docker_container:
    name: old-app
    state: absent

# Prune unused images - community.docker.docker_prune: images: true images_filters: dangling: true

Full Stack Deployment

- hosts: docker_hosts
  become: true
  tasks:
    - docker_network:
        name: mystack
    - docker_container:
        name: db
        image: postgres:16
        networks: [{ name: mystack }]
        volumes: [db_data:/var/lib/postgresql/data]
        env: { POSTGRES_PASSWORD: "{{ vault_db_pass }}" }
    - docker_container:
        name: app
        image: "myorg/myapp:{{ app_version }}"
        networks: [{ name: mystack }]
        ports: ["8080:8080"]
        env: { DATABASE_URL: "postgresql://db:5432/myapp" }

FAQ

community.docker vs docker module?

community.docker is the current maintained collection. The old docker_container short name resolves to it via ansible.legacy.

How to install Docker itself?

Use geerlingguy.docker role: ansible-galaxy install geerlingguy.docker.

Docker vs Podman?

Use containers.podman collection for Podman. API is similar but modules differ.

Related Articles

using Ansible Galaxy for collectionstask-scoped environment variables in Ansibleidempotent restarts via Ansible handlersAnsible Vault CLI referenceAnsible become methods compared

Category: installation

Browse all Ansible tutorials · AnsiblePilot Home