Files
2025-11-30 08:47:38 +08:00

6.2 KiB

Docker Deployment with Ansible

Managing Docker containers and compose stacks via Ansible.

Collection Setup

ansible-galaxy collection install community.docker

Deploy from local compose file

- name: Deploy application stack
  hosts: docker_hosts
  become: true
  tasks:
    - name: Create project directory
      ansible.builtin.file:
        path: /opt/myapp
        state: directory
        owner: "{{ ansible_user }}"
        mode: '0755'

    - name: Copy compose file
      ansible.builtin.template:
        src: docker-compose.yml.j2
        dest: /opt/myapp/docker-compose.yml
        owner: "{{ ansible_user }}"
        mode: '0644'

    - name: Copy environment file
      ansible.builtin.template:
        src: .env.j2
        dest: /opt/myapp/.env
        owner: "{{ ansible_user }}"
        mode: '0600'

    - name: Deploy with compose
      community.docker.docker_compose_v2:
        project_src: /opt/myapp
        state: present
        pull: always
      register: deploy_result

    - name: Show deployed services
      ansible.builtin.debug:
        var: deploy_result.containers

Compose operations

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

# Stop stack (keep volumes)
- name: Stop stack
  community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: stopped

# Remove stack
- name: Remove stack
  community.docker.docker_compose_v2:
    project_src: /opt/myapp
    state: absent
    remove_volumes: false  # Keep data volumes

Container Deployment (Individual)

Run container

- name: Run nginx container
  community.docker.docker_container:
    name: nginx
    image: nginx:1.25
    state: started
    restart_policy: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /opt/nginx/html:/usr/share/nginx/html:ro
      - /opt/nginx/conf.d:/etc/nginx/conf.d:ro
    env:
      TZ: "America/Los_Angeles"
    labels:
      app: web
      env: production

- name: Run database
  community.docker.docker_container:
    name: postgres
    image: postgres:15
    state: started
    restart_policy: unless-stopped
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
    env:
      POSTGRES_USER: "{{ db_user }}"
      POSTGRES_PASSWORD: "{{ db_password }}"
      POSTGRES_DB: "{{ db_name }}"
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U {{ db_user }}"]
      interval: 10s
      timeout: 5s
      retries: 5

Container lifecycle

# Stop container
- name: Stop container
  community.docker.docker_container:
    name: myapp
    state: stopped

# Restart container
- name: Restart container
  community.docker.docker_container:
    name: myapp
    state: started
    restart: true

# Remove container
- name: Remove container
  community.docker.docker_container:
    name: myapp
    state: absent

# Force recreate
- name: Recreate container
  community.docker.docker_container:
    name: myapp
    image: myapp:latest
    state: started
    recreate: true

Image Management

# Pull image
- name: Pull latest image
  community.docker.docker_image:
    name: myapp
    tag: latest
    source: pull
    force_source: true  # Always check for updates

# Build from Dockerfile
- name: Build image
  community.docker.docker_image:
    name: myapp
    tag: "{{ version }}"
    source: build
    build:
      path: /opt/myapp
      dockerfile: Dockerfile
      pull: true  # Pull base image updates

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

Network Management

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

# Create macvlan network
- name: Create macvlan network
  community.docker.docker_network:
    name: lan
    driver: macvlan
    driver_options:
      parent: eth0
    ipam_config:
      - subnet: 192.168.1.0/24
        gateway: 192.168.1.1

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

Volume Management

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

# Create volume with options
- name: Create NFS volume
  community.docker.docker_volume:
    name: shared_data
    driver: local
    driver_options:
      type: nfs
      device: ":/exports/data"
      o: "addr=192.168.1.10,rw"

# Backup volume
- name: Backup volume
  community.docker.docker_container:
    name: backup
    image: alpine
    command: tar czf /backup/data.tar.gz /data
    volumes:
      - app_data:/data:ro
      - /opt/backups:/backup
    auto_remove: true

Common Patterns

Wait for service health

- name: Deploy database
  community.docker.docker_container:
    name: postgres
    image: postgres:15
    # ... config ...

- name: Wait for database
  community.docker.docker_container_info:
    name: postgres
  register: db_info
  until: db_info.container.State.Health.Status == "healthy"
  retries: 30
  delay: 2

Rolling update

- name: Pull new image
  community.docker.docker_image:
    name: myapp
    tag: "{{ new_version }}"
    source: pull

- name: Update container
  community.docker.docker_container:
    name: myapp
    image: "myapp:{{ new_version }}"
    state: started
    recreate: true
    restart_policy: unless-stopped

Cleanup

- name: Remove stopped containers
  community.docker.docker_prune:
    containers: true
    containers_filters:
      status: exited

- name: Remove unused images
  community.docker.docker_prune:
    images: true
    images_filters:
      dangling: true

- name: Full cleanup (careful!)
  community.docker.docker_prune:
    containers: true
    images: true
    networks: true
    volumes: false  # Don't remove data!
    builder_cache: true