Ansible docker Module: Deploy Docker Container ด้วย Ansible

Ansible docker_container module (ส่วนหนึ่งของ community.docker collection) ใช้ deploy และจัดการ container บน remote server โดยตรงใน Playbook ครอบคลุมการสร้าง, หยุด, ลบ container, กำหนด environment variables, volumes, networks และ restart policy โดยไม่ต้องรัน docker run ตรง ๆ ซึ่งไม่ idempotent

บทความนี้อธิบายการติดตั้ง collection, parameters หลัก, การใช้ docker_image pull image, การจัดการ network และ volume และ pattern สำหรับ deploy multi-container application stack

ติดตั้ง community.docker Collection

ก่อนใช้ docker_container module ต้องติดตั้ง community.docker collection ก่อน และ remote server ต้องมี daemon และ Python SDK ของ container engine ติดตั้งอยู่

# ติดตั้ง collection บน control node
ansible-galaxy collection install community.docker

# ติดตั้ง Python Docker SDK บน remote server (ทำผ่าน Playbook)
- name: Install Docker Python SDK
  pip:
    name: docker
    state: present

docker_container Module พื้นฐาน

module นี้ควบคุมสถานะของ container ผ่าน state parameter รองรับ started, stopped, absent และ present ทำงาน idempotent — ถ้า container อยู่ในสถานะที่ต้องการแล้วจะไม่ทำอะไร

---
- name: Basic docker_container usage
  hosts: all
  become: true
  collections:
    - community.docker

  tasks:
    # run container (started = create + start)
    - name: Run nginx container
      docker_container:
        name: nginx
        image: nginx:latest
        state: started
        restart_policy: always
        ports:
          - "80:80"
          - "443:443"

    # หยุด container โดยไม่ลบ
    - name: Stop container
      docker_container:
        name: nginx
        state: stopped

    # ลบ container
    - name: Remove container
      docker_container:
        name: nginx
        state: absent

    # present = สร้าง container แต่ไม่ start
    - name: Create container without starting
      docker_container:
        name: myapp
        image: myapp:v2
        state: present

Environment Variables, Volumes และ Networks

กำหนด environment variables ผ่าน env, mount volumes ผ่าน volumes และเชื่อมต่อ virtual network ผ่าน networks

---
- name: Container with env, volumes and networks
  hosts: all
  become: true
  vars:
    db_password: "{{ vault_db_password }}"

  tasks:
    - name: Run application container
      community.docker.docker_container:
        name: myapp
        image: "myapp:{{ app_version }}"
        state: started
        restart_policy: unless-stopped

        # environment variables
        env:
          APP_ENV: production
          DB_HOST: db
          DB_PORT: "5432"
          DB_PASS: "{{ db_password }}"
          LOG_LEVEL: info

        # volume mounts
        volumes:
          - /opt/myapp/data:/app/data
          - /opt/myapp/logs:/app/logs
          - /etc/myapp/app.conf:/app/config/app.conf:ro

        # network connections
        networks:
          - name: app_network
          - name: db_network

        # port bindings
        ports:
          - "127.0.0.1:8080:8080"

docker_image — Pull และ Build Image

docker_image module ใช้ pull image จาก registry หรือ build จาก Dockerfile บน remote server ก่อนที่จะ run container ช่วยลด downtime เพราะ image พร้อมก่อนสั่ง start

---
- name: Docker image management
  hosts: all
  become: true

  tasks:
    # pull image จาก Docker Hub
    - name: Pull application image
      community.docker.docker_image:
        name: nginx
        tag: "1.25"
        source: pull

    # pull image จาก private registry
    - name: Pull from private registry
      community.docker.docker_image:
        name: registry.example.com/myapp
        tag: "{{ app_version }}"
        source: pull
        force_source: true    # pull ใหม่แม้มีอยู่แล้ว

    # build จาก Dockerfile (ต้อง copy Dockerfile ไปก่อน)
    - name: Build image from Dockerfile
      community.docker.docker_image:
        name: myapp
        tag: "{{ app_version }}"
        source: build
        build:
          path: /opt/myapp/docker
          dockerfile: Dockerfile.prod
        force_source: true

    # ลบ image ที่ไม่ต้องการ
    - name: Remove old image
      community.docker.docker_image:
        name: myapp
        tag: "{{ old_version }}"
        state: absent

Docker Network และ Volume

สร้าง network และ named volume ก่อน deploy container เพื่อให้ container สื่อสารกันได้ผ่าน bridge network และข้อมูลคงอยู่แม้ลบ container ทิ้ง

---
- name: Docker network and volume setup
  hosts: all
  become: true

  tasks:
    # สร้าง custom bridge network
    - name: Create application network
      community.docker.docker_network:
        name: app_network
        driver: bridge
        state: present

    # สร้าง named volume สำหรับเก็บข้อมูล
    - name: Create database volume
      community.docker.docker_volume:
        name: db_data
        state: present

    - name: Create logs volume
      community.docker.docker_volume:
        name: app_logs
        state: present

    # run database container ที่ใช้ volume และ network
    - name: Run PostgreSQL container
      community.docker.docker_container:
        name: postgres
        image: postgres:15
        state: started
        restart_policy: always
        env:
          POSTGRES_DB: appdb
          POSTGRES_USER: appuser
          POSTGRES_PASSWORD: "{{ vault_db_password }}"
        volumes:
          - db_data:/var/lib/postgresql/data
        networks:
          - name: app_network

Pattern: Deploy Multi-Container Application

ตัวอย่าง Playbook deploy web application stack ที่ประกอบด้วย Nginx, แอปพลิเคชัน และ PostgreSQL โดยใช้ network แยก frontend กับ backend

---
- name: Deploy web application stack
  hosts: appservers
  become: true
  vars:
    app_version: "{{ deploy_version | default('latest') }}"
    app_image: registry.example.com/myapp

  tasks:
    # สร้าง networks
    - name: Create networks
      community.docker.docker_network:
        name: "{{ item }}"
        state: present
      loop:
        - frontend_net
        - backend_net

    # สร้าง volumes
    - name: Create persistent volumes
      community.docker.docker_volume:
        name: "{{ item }}"
        state: present
      loop:
        - postgres_data
        - app_uploads

    # pull image ล่าสุด
    - name: Pull application image
      community.docker.docker_image:
        name: "{{ app_image }}"
        tag: "{{ app_version }}"
        source: pull
        force_source: true

    # deploy database
    - name: Deploy PostgreSQL
      community.docker.docker_container:
        name: postgres
        image: postgres:15
        state: started
        restart_policy: always
        env:
          POSTGRES_DB: appdb
          POSTGRES_USER: "{{ db_user }}"
          POSTGRES_PASSWORD: "{{ vault_db_password }}"
        volumes:
          - postgres_data:/var/lib/postgresql/data
        networks:
          - name: backend_net

    # deploy application
    - name: Deploy application
      community.docker.docker_container:
        name: myapp
        image: "{{ app_image }}:{{ app_version }}"
        state: started
        restart_policy: unless-stopped
        env:
          DATABASE_URL: "postgresql://{{ db_user }}:{{ vault_db_password }}@postgres/appdb"
          SECRET_KEY: "{{ vault_secret_key }}"
        volumes:
          - app_uploads:/app/uploads
        networks:
          - name: frontend_net
          - name: backend_net

    # deploy Nginx reverse proxy
    - name: Deploy Nginx
      community.docker.docker_container:
        name: nginx
        image: nginx:latest
        state: started
        restart_policy: always
        ports:
          - "80:80"
          - "443:443"
        volumes:
          - /etc/nginx/conf.d:/etc/nginx/conf.d:ro
          - /etc/ssl/certs:/etc/ssl/certs:ro
        networks:
          - name: frontend_net

สรุป

docker_container module จาก community.docker collection ทำให้จัดการ container ด้วย Ansible ได้อย่าง idempotent รองรับ state ครบทั้ง started, stopped, absent และ present พร้อม environment variables, volumes, networks และ restart policy

Pattern ที่ควรจำ: สร้าง network และ volume ก่อน deploy container เสมอ, ใช้ docker_image pull image ล่วงหน้าเพื่อลด downtime, เก็บ passwords และ secrets ใน Ansible Vault แล้วส่งผ่าน env และใช้ restart_policy: unless-stopped สำหรับ production service ที่ต้องการ auto-restart