community.docker collection ให้ modules สำหรับ manage Docker containers, images, networks และ volumes โดยตรงจาก Ansible playbook — แทนที่การรัน docker run หรือ docker-compose ด้วยตนเอง ทำให้ deployment เป็น idempotent และ repeatable
บทความนี้อธิบายการ install community.docker collection, manage containers ด้วย docker_container module, จัดการ images และ networks, ใช้ Docker Compose ผ่าน docker_compose_v2 module และ pattern สำหรับ deploy multi-container applications บน VPS จริง
ติดตั้งและ Prerequisites
community.docker collection ต้องการ Docker SDK สำหรับ Python บน control node และ target host ที่มี Docker Engine ทำงานอยู่
# ติดตั้ง community.docker collection
ansible-galaxy collection install community.docker:3.10.0
# ติดตั้ง Docker SDK บน control node (Python dependency)
pip install docker
# requirements.yml
---
collections:
- name: community.docker
version: "3.10.0"
# ตรวจสอบ Docker ทำงานบน target host
- name: Check Docker is running
ansible.builtin.service:
name: docker
state: started
enabled: true
docker_container — จัดการ Containers
Module หลักสำหรับ manage Docker containers — สร้าง, start, stop, remove และ update container configuration ด้วย idempotency
# รัน Nginx container พื้นฐาน
- name: Start Nginx container
community.docker.docker_container:
name: mynginx
image: nginx:1.25
state: started
restart_policy: always
ports:
- "80:80"
- "443:443"
volumes:
- /etc/nginx/conf.d:/etc/nginx/conf.d:ro
- /var/www/html:/usr/share/nginx/html:ro
# Container states ที่ใช้บ่อย:
# started — ถ้าไม่มีให้สร้าง, ถ้าหยุดอยู่ให้ start
# present — สร้างแต่ไม่ start
# stopped — หยุด container ที่ทำงานอยู่
# absent — ลบ container (หยุดก่อนถ้าทำงานอยู่)
# restarted — restart container
# ลบ container
- name: Remove old container
community.docker.docker_container:
name: mynginx
state: absent
# Container พร้อม environment variables และ resource limits
- name: Deploy application container
community.docker.docker_container:
name: myapp
image: "myregistry.example.com/myapp:{{ app_version }}"
state: started
restart_policy: unless-stopped
env:
DATABASE_URL: "postgresql://{{ db_user }}:{{ db_pass }}@postgres:5432/myapp"
REDIS_URL: "redis://redis:6379/0"
SECRET_KEY: "{{ app_secret_key }}"
DEBUG: "false"
ports:
- "8000:8000"
networks:
- name: app_network
memory: "512m"
cpus: 0.5
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
log_driver: json-file
log_options:
max-size: "10m"
max-file: "3"
docker_image — จัดการ Images
Pull images จาก registry, build จาก Dockerfile, tag และลบ images เก่าที่ไม่ใช้แล้ว
# Pull image จาก Docker Hub
- name: Pull latest Postgres image
community.docker.docker_image:
name: postgres
tag: "16"
source: pull
# Pull จาก private registry
- name: Pull application image
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: pull
force_source: true # pull แม้ tag นั้นมีอยู่แล้ว
# Login private registry ก่อน pull
- name: Login to private registry
community.docker.docker_login:
registry_url: registry.example.com
username: "{{ registry_user }}"
password: "{{ registry_password }}"
# Build image จาก Dockerfile
- name: Build custom image
community.docker.docker_image:
name: myapp
tag: "{{ app_version }}"
source: build
build:
path: /opt/myapp
dockerfile: Dockerfile
args:
BUILD_DATE: "{{ ansible_date_time.iso8601 }}"
VERSION: "{{ app_version }}"
push: true
# ลบ image เก่า
- name: Remove old images
community.docker.docker_image:
name: myapp
tag: "{{ old_version }}"
state: absent
docker_network และ docker_volume
สร้าง isolated networks สำหรับ container communication และ volumes สำหรับ persistent data ก่อน deploy containers ที่ใช้งาน
# สร้าง custom bridge network
- name: Create application network
community.docker.docker_network:
name: app_network
driver: bridge
ipam_config:
- subnet: "172.20.0.0/16"
gateway: "172.20.0.1"
# สร้าง volumes สำหรับ persistent data
- name: Create database volume
community.docker.docker_volume:
name: postgres_data
state: present
- name: Create app uploads volume
community.docker.docker_volume:
name: app_uploads
state: present
# ใช้ network และ volume ใน container
- name: Start PostgreSQL with persistent storage
community.docker.docker_container:
name: postgres
image: postgres:16
state: started
restart_policy: always
env:
POSTGRES_DB: myapp
POSTGRES_USER: "{{ db_user }}"
POSTGRES_PASSWORD: "{{ db_password }}"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- name: app_network
docker_compose_v2 — Multi-Container Deployment
docker_compose_v2 module ใช้ Docker Compose V2 (docker compose plugin) เพื่อ manage multi-container applications — อ่าน compose file และ sync state กับที่กำหนด
# deploy จาก docker-compose.yml ที่มีอยู่แล้ว
- name: Deploy application stack
community.docker.docker_compose_v2:
project_src: /opt/myapp
state: present
# เทียบเท่า: docker compose up -d
# ระบุ compose file เฉพาะ
- name: Deploy with override file
community.docker.docker_compose_v2:
project_src: /opt/myapp
files:
- docker-compose.yml
- docker-compose.prod.yml
state: present
# Pull images ก่อน deploy
- name: Update and deploy
community.docker.docker_compose_v2:
project_src: /opt/myapp
pull: always
state: present
# หยุด stack (ไม่ลบ volumes)
- name: Stop application stack
community.docker.docker_compose_v2:
project_src: /opt/myapp
state: stopped
# ลบ stack พร้อม volumes
- name: Remove application stack
community.docker.docker_compose_v2:
project_src: /opt/myapp
remove_volumes: true
state: absent
Playbook ครบวงจร: Deploy Web Stack บน VPS
ตัวอย่าง playbook ที่ deploy web application stack (Nginx + App + PostgreSQL + Redis) บน VPS ตั้งแต่ต้นจนจบ
---
# deploy_stack.yml — deploy containerized web application
- name: Deploy web application stack
hosts: appservers
become: true
vars:
app_version: "1.2.0"
app_dir: /opt/myapp
tasks:
# 1. ติดตั้ง Docker
- name: Install Docker prerequisites
ansible.builtin.apt:
name:
- docker.io
- docker-compose-plugin
- python3-docker
state: present
update_cache: true
- name: Start Docker service
ansible.builtin.systemd:
name: docker
state: started
enabled: true
# 2. สร้าง infrastructure
- name: Create app network
community.docker.docker_network:
name: app_network
state: present
- name: Create persistent volumes
community.docker.docker_volume:
name: "{{ item }}"
state: present
loop:
- postgres_data
- redis_data
- app_uploads
# 3. Deploy databases
- name: Start PostgreSQL
community.docker.docker_container:
name: postgres
image: postgres:16
state: started
restart_policy: always
env:
POSTGRES_DB: myapp
POSTGRES_USER: "{{ vault_db_user }}"
POSTGRES_PASSWORD: "{{ vault_db_password }}"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- name: app_network
- name: Start Redis
community.docker.docker_container:
name: redis
image: redis:7-alpine
state: started
restart_policy: always
volumes:
- redis_data:/data
networks:
- name: app_network
# 4. Copy application files
- name: Create app directory
ansible.builtin.file:
path: "{{ app_dir }}"
state: directory
mode: "0755"
- name: Upload compose file
ansible.builtin.template:
src: docker-compose.yml.j2
dest: "{{ app_dir }}/docker-compose.yml"
mode: "0644"
# 5. Pull และ deploy application
- name: Pull application image
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: pull
force_source: true
- name: Deploy application container
community.docker.docker_container:
name: myapp
image: "registry.example.com/myapp:{{ app_version }}"
state: started
restart_policy: unless-stopped
env:
DATABASE_URL: "postgresql://{{ vault_db_user }}:{{ vault_db_password }}@postgres:5432/myapp"
REDIS_URL: "redis://redis:6379/0"
SECRET_KEY: "{{ vault_secret_key }}"
networks:
- name: app_network
volumes:
- app_uploads:/app/uploads
# 6. Deploy Nginx reverse proxy
- name: Copy Nginx config
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/conf.d/myapp.conf
- name: Start Nginx container
community.docker.docker_container:
name: nginx
image: nginx:1.25
state: started
restart_policy: always
ports:
- "80:80"
- "443:443"
volumes:
- /etc/nginx/conf.d:/etc/nginx/conf.d:ro
- /etc/ssl:/etc/ssl:ro
networks:
- name: app_network
Rolling Update Pattern
Update container โดยไม่ downtime — pull image ใหม่ แล้ว recreate container ด้วย image ล่าสุด Ansible จัดการ sequence ให้อัตโนมัติ
---
# rolling_update.yml
- name: Rolling update application
hosts: appservers
become: true
serial: 1 # อัพเดตทีละ 1 host
vars:
app_version: "{{ new_version }}"
tasks:
- name: Pull new image
community.docker.docker_image:
name: "registry.example.com/myapp"
tag: "{{ app_version }}"
source: pull
force_source: true
- name: Stop old container gracefully
community.docker.docker_container:
name: myapp
state: stopped
- name: Start new container
community.docker.docker_container:
name: myapp
image: "registry.example.com/myapp:{{ app_version }}"
state: started
restart_policy: unless-stopped
# ... env, networks, volumes เหมือนเดิม
- name: Wait for container to be healthy
community.docker.docker_container_info:
name: myapp
register: container_info
until: container_info.container.State.Health.Status == "healthy"
retries: 10
delay: 10
สรุป
community.docker collection ทำให้ Docker container management เป็น idempotent เหมือน infrastructure resource อื่น × — ใช้ docker_container สำหรับ lifecycle management, docker_image สำหรับ image operations, docker_network และ docker_volume สำหรับ infrastructure setup และ docker_compose_v2 สำหรับ multi-container stacks
ข้อดีหลักคือ playbook ที่รัน 2 ครั้งจะได้ผลเหมือนกัน ต่างจากการรัน docker run ด้วยตนเองที่ต้องตรวจสอบ state ก่อนทุกครั้ง — เหมาะสำหรับ automated deployment pipeline ใน production

