ai

Docker Compose — จัด Multi-Container อย่างมือโปร 2026

Docker Compose — จัด Multi-Container อย่างมือโปร 2026

Docker Compose คืออะไรทำไมต้องใช้

Docker Compose — จัด Multi-Container อย่างมือโปร 2026

ถ้าคุณเคยรัน docker run ที่มี option ยาวเป็นหางว่าวแล้วต้องทำซ้ำทุกครั้งที่ต้องการสร้าง container ใหม่ Docker Compose คือทางออกผมใช้ Docker มาตั้งแต่ version 1.0 ปี 2014 และผมบอกได้เลยว่า Docker Compose เปลี่ยนวิธีการทำงานของผมไปอย่างสิ้นเชิงจากที่ต้องจำ command ยาวๆกลายเป็นแค่เขียน YAML file แล้วรัน docker compose up

Docker Compose เป็นเครื่องมือสำหรับ define และ run multi-container Docker applications คุณเขียน YAML file อธิบายว่า application ต้องการ services อะไรบ้างใช้ image ไหนต่อ network ยังไง mount volume ที่ไหนแล้ว Compose จัดการสร้างทุกอย่างให้ในคำสั่งเดียว

Compose V1 vs V2 — ต้องใช้ตัวไหน

ตั้งแต่ปี 2023 Docker Compose V1 (ที่เรียกด้วย docker-compose มี hyphen) ถูก deprecate แล้วตอนนี้ต้องใช้ V2 ที่เรียกด้วย docker compose (ไม่มี hyphen เป็น subcommand ของ docker) V2 เขียนด้วย Go แทน Python ทำให้เร็วกว่าเดิมมากและรองรับ feature ใหม่ๆเช่น profiles, service dependencies ที่ดีขึ้นและ watch mode สำหรับ development

เมื่อไหร่ควรใช้ Compose เมื่อไหร่ควรใช้ Kubernetes

คำถามนี้ผมถูกถามบ่อยมากผมตอบแบบตรงๆเลยว่าถ้า application ของคุณรันบนเครื่องเดียวหรือ 2-3 เครื่องใช้ Compose ถ้าต้อง scale ข้าม 10+ เครื่องต้อง auto-scaling ต้อง rolling update ที่ซับซ้อนถึงค่อยใช้ Kubernetes ผมเจอหลายบริษัทที่ใช้ Kubernetes ทั้งที่มี server แค่ 3 เครื่องมันเหมือนใช้ปืนใหญ่ยิงนก overhead เยอะเกินไป

ติดตั้ง Docker Compose V2

Docker Compose V2 มาพร้อมกับ Docker Desktop อยู่แล้วแต่ถ้าใช้ Docker Engine บน Linux server ต้องติดตั้งแยก

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ Roic คืออะไร — คู่มือฉบับสมบูรณ์ 2026

ติดตั้งบน Ubuntu/Debian

# ติดตั้ง Docker Engine (ถ้ายังไม่มี)


curl -fsSL https://get.docker.com | sh


sudo usermod -aG docker $USER





# Docker Compose V2 มาพร้อม Docker Engine แล้ว


# ตรวจสอบ version


docker compose version


# Docker Compose version v2.27.0





# ถ้าต้องการ update เฉพาะ Compose plugin


sudo apt update


sudo apt install docker-compose-plugin





# ทดสอบ


docker compose version

ติดตั้งบน CentOS/Rocky Linux

# ติดตั้ง Docker repo


sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo





# ติดตั้ง Docker + Compose


sudo dnf install docker-ce docker-ce-cli containerd.io docker-compose-plugin





# เริ่ม Docker service


sudo systemctl enable --now docker





# ตรวจสอบ


docker compose version

เขียน docker-compose.yml ไฟล์แรก

ผมจะเริ่มจากตัวอย่างง่ายๆแล้วค่อยเพิ่มความซับซ้อนทีละนิดวิธีนี้ผมสอนมาหลายรุ่นแล้วเรียนรู้ได้เร็วที่สุด

ตัวอย่าง: Nginx Web Server

# docker-compose.yml


services:


 web:


 image: nginx:alpine


 ports:


 - "8080:80"


 volumes:


 - ./html:/usr/share/nginx/html:ro


 restart: unless-stopped
# สร้าง HTML file


mkdir html


echo "<h1>Hello from Docker Compose</h1>" > html/index.html





# Start


docker compose up -d





# ดู logs


docker compose logs -f web





# หยุด


docker compose down

ทำความเข้าใจ YAML Structure

ไฟล์ docker-compose.yml มี top-level keys หลักๆดังนี้ services คือ containers ที่ต้องการ run ทุก service จะถูกสร้างเป็น container volumes คือ named volumes สำหรับเก็บ data ถาวร networks คือ custom networks สำหรับ container communication secrets คือ sensitive data เช่น passwords, API keys configs คือ configuration files ที่ mount เข้า container

ตัวอย่าง: Full-Stack Application

# docker-compose.yml — Node.js + PostgreSQL + Redis


services:


 app:


 build:


 context: .


 dockerfile: Dockerfile


 ports:


 - "3000:3000"


 environment:


 - NODE_ENV=production


 - DATABASE_URL=postgresql://appuser:secretpass@db:5432/myapp


 - REDIS_URL=redis://cache:6379


 depends_on:


 db:


 condition: service_healthy


 cache:


 condition: service_started


 restart: unless-stopped


 networks:


 - app-network





 db:


 image: postgres:16-alpine


 environment:


 POSTGRES_DB: myapp


 POSTGRES_USER: appuser


 POSTGRES_PASSWORD: secretpass


 volumes:


 - postgres-data:/var/lib/postgresql/data


 - ./init.sql:/docker-entrypoint-initdb.d/init.sql


 healthcheck:


 test: ["CMD-SHELL", "pg_isready -U appuser -d myapp"]


 interval: 10s


 timeout: 5s


 retries: 5


 restart: unless-stopped


 networks:


 - app-network





 cache:


 image: redis:7-alpine


 command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru


 volumes:


 - redis-data:/data


 restart: unless-stopped


 networks:


 - app-network





volumes:


 postgres-data:


 redis-data:





networks:


 app-network:


 driver: bridge

สังเกตว่าผมใช้ depends_on กับ condition: service_healthy ซึ่งเป็น feature ของ Compose V2 ที่ดีมากมันจะรอจนกว่า PostgreSQL จะ ready จริงๆถึงค่อย start app ไม่ใช่แค่รอจน container start เท่านั้น

แนะนำเพิ่มเติม — หนังสือเทรดที่ SiamCafeBook

Networking ใน Docker Compose

เรื่อง Networking เป็นจุดที่หลายคนสับสนผมจะอธิบายให้ชัดเจน

Default Network

เมื่อรัน docker compose up Compose จะสร้าง default network ให้อัตโนมัติชื่อว่า {project_name}_default ทุก service ในไฟล์ compose จะอยู่ใน network นี้และสามารถติดต่อกันได้ผ่าน service name เช่น app สามารถเชื่อมต่อ database ได้โดยใช้ hostname db ตรงๆเลยไม่ต้องรู้ IP address

เนื้อหาเกี่ยวข้อง — ทำความเข้าใจ Python Click CLI Domain Driven Design DDD

Custom Networks

# แยก network สำหรับ frontend และ backend


services:


 nginx:


 image: nginx:alpine


 ports:


 - "80:80"


 networks:


 - frontend





 app:


 build: .


 networks:


 - frontend


 - backend





 db:


 image: postgres:16-alpine


 networks:


 - backend





networks:


 frontend:


 driver: bridge


 backend:


 driver: bridge


 internal: true # ไม่ให้เข้าถึงจากภายนอก

ในตัวอย่างนี้ nginx เข้าถึง app ได้แต่เข้าถึง db ไม่ได้เพราะอยู่คนละ network ส่วน app เข้าถึงได้ทั้ง nginx และ db เพราะอยู่ทั้ง 2 networks วิธีนี้เพิ่ม security เพราะถ้า nginx ถูก compromise ก็เข้าถึง database ไม่ได้โดยตรง

External Networks

# เชื่อมต่อกับ network ที่มีอยู่แล้ว


# เช่น network ที่สร้างจาก Compose project อื่น


networks:


 shared:


 external: true


 name: monitoring_network





# สร้าง external network ก่อน


# docker network create monitoring_network

Volumes และ Data Persistence

Docker Compose — จัด Multi-Container อย่างมือโปร 2026

ปัญหาใหญ่ที่สุดของ Container คือเมื่อ container ถูกลบ data ก็หายไปด้วย Volumes คือทางออก

Named Volumes vs Bind Mounts

Named Volumes ถูกจัดการโดย Docker เก็บใน /var/lib/docker/volumes/ เหมาะสำหรับ data ที่ container เป็นคนเขียนเช่น database files ส่วน Bind Mounts คือ mount directory จาก host เข้า container เหมาะสำหรับ source code หรือ config files ที่ต้องการแก้ไขจาก host

services:


 db:


 image: mysql:8.0


 volumes:


 # Named volume สำหรับ database data


 - mysql-data:/var/lib/mysql


 # Bind mount สำหรับ custom config


 - ./my.cnf:/etc/mysql/conf.d/custom.cnf:ro


 # Bind mount สำหรับ backup


 - /backup/mysql:/backup





 app:


 build: .


 volumes:


 # Bind mount source code สำหรับ development


 - ./src:/app/src


 # Named volume สำหรับ node_modules (ไม่ sync กับ host)


 - node_modules:/app/node_modules





volumes:


 mysql-data:


 driver: local


 node_modules:

Volume Backup

# Backup named volume


docker run --rm \


 -v mysql-data:/source:ro \


 -v /backup:/backup \


 alpine tar czf /backup/mysql-data-$(date +%Y%m%d).tar.gz -C /source .





# Restore


docker run --rm \


 -v mysql-data:/target \


 -v /backup:/backup \


 alpine tar xzf /backup/mysql-data-20260228.tar.gz -C /target

ตัวอย่างจริง: WordPress + MySQL + Redis

ผมจะแสดง Production-grade Docker Compose สำหรับ WordPress ที่ผมใช้จริงมี MySQL สำหรับ database, Redis สำหรับ object cache และ Nginx เป็น reverse proxy พร้อม SSL

แนะนำเพิ่มเติม — ดูสัญญาณเทรดที่ XM Signal

# docker-compose.yml — Production WordPress


services:


 nginx:


 image: nginx:alpine


 ports:


 - "80:80"


 - "443:443"


 volumes:


 - ./nginx/conf.d:/etc/nginx/conf.d:ro


 - ./nginx/ssl:/etc/nginx/ssl:ro


 - wordpress-data:/var/www/html:ro


 depends_on:


 - wordpress


 restart: unless-stopped


 networks:


 - frontend





 wordpress:


 image: wordpress:6.5-php8.3-fpm-alpine


 environment:


 WORDPRESS_DB_HOST: mysql


 WORDPRESS_DB_USER: wp_user


 WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password


 WORDPRESS_DB_NAME: wordpress


 WORDPRESS_CONFIG_EXTRA: |


 define('WP_REDIS_HOST', 'redis');


 define('WP_REDIS_PORT', 6379);


 define('WP_CACHE', true);


 define('WP_MEMORY_LIMIT', '256M');


 volumes:


 - wordpress-data:/var/www/html


 - ./uploads.ini:/usr/local/etc/php/conf.d/uploads.ini


 secrets:


 - db_password


 depends_on:


 mysql:


 condition: service_healthy


 redis:


 condition: service_started


 restart: unless-stopped


 networks:


 - frontend


 - backend





 mysql:


 image: mysql:8.0


 environment:


 MYSQL_DATABASE: wordpress


 MYSQL_USER: wp_user


 MYSQL_PASSWORD_FILE: /run/secrets/db_password


 MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password


 volumes:


 - mysql-data:/var/lib/mysql


 - ./mysql/conf.d:/etc/mysql/conf.d:ro


 secrets:


 - db_password


 - db_root_password


 healthcheck:


 test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]


 interval: 10s


 timeout: 5s


 retries: 5


 restart: unless-stopped


 networks:


 - backend





 redis:


 image: redis:7-alpine


 command: redis-server --maxmemory 128mb --maxmemory-policy allkeys-lru --save 60 1000


 volumes:


 - redis-data:/data


 restart: unless-stopped


 networks:


 - backend





volumes:


 wordpress-data:


 mysql-data:


 redis-data:





networks:


 frontend:


 backend:


 internal: true





secrets:


 db_password:


 file: ./secrets/db_password.txt


 db_root_password:


 file: ./secrets/db_root_password.txt

Nginx Configuration สำหรับ WordPress

# nginx/conf.d/wordpress.conf


server {


 listen 80;


 server_name example.com;


 return 301 https://$server_name$request_uri;


}





server {


 listen 443 ssl http2;


 server_name example.com;





 ssl_certificate /etc/nginx/ssl/fullchain.pem;


 ssl_certificate_key /etc/nginx/ssl/privkey.pem;





 root /var/www/html;


 index index.php;





 client_max_body_size 64M;





 location / {


 try_files $uri $uri/ /index.php?$args;


 }





 location ~ \.php$ {


 fastcgi_pass wordpress:9000;


 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;


 include fastcgi_params;


 fastcgi_buffer_size 128k;


 fastcgi_buffers 4 256k;


 }





 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2)$ {


 expires 30d;


 add_header Cache-Control "public, immutable";


 }


}

Production-Ready Compose

หลายคนใช้ Docker Compose แค่สำหรับ development แต่จริงๆมันใช้ production ได้ดีถ้าตั้งค่าถูกต้อง

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: React Query TanStack Container Orchestration — คู่มือฉบับสมบูรณ์ 2026

Resource Limits

services:


 app:


 image: myapp:latest


 deploy:


 resources:


 limits:


 cpus: '2.0'


 memory: 512M


 reservations:


 cpus: '0.5'


 memory: 256M


 # Compose V2 รองรับ deploy section แม้ไม่ได้ใช้ Swarm

Health Checks ที่ดี

services:


 app:


 image: myapp:latest


 healthcheck:


 test: ["CMD", "curl", "-f", "http://localhost:3000/health"]


 interval: 30s


 timeout: 10s


 retries: 3


 start_period: 40s # รอ app start ก่อน

Logging Configuration

services:


 app:


 image: myapp:latest


 logging:


 driver: json-file


 options:


 max-size: "10m"


 max-file: "3"


 compress: "true"


 # หรือส่ง log ไป centralized logging


 # ดูบทความ ELK Stack ที่ผมเขียนไว้

สำหรับ centralized logging ผมแนะนำให้อ่านบทความ Elasticsearch ELK Stack ที่ผมเขียนไว้ใช้คู่กับ Docker ได้ดีมาก

Docker Compose Watch (Development)

# Feature ใหม่ของ Compose V2 สำหรับ live development


services:


 app:


 build: .


 develop:


 watch:


 - action: sync


 path: ./src


 target: /app/src


 - action: rebuild


 path: ./package.json





# รัน development mode


docker compose watch


# เมื่อแก้ไฟล์ใน ./src จะ sync เข้า container อัตโนมัติ


# เมื่อแก้ package.json จะ rebuild image ใหม่

Profiles สำหรับแยก Environment

services:


 app:


 image: myapp:latest


 # รันเสมอ ไม่ต้องระบุ profile





 debug-tools:


 image: nicolaka/netshoot


 profiles: ["debug"]


 # รันเฉพาะเมื่อระบุ profile





 monitoring:


 image: prom/prometheus


 profiles: ["monitoring"]





# รัน default services


docker compose up -d





# รัน พร้อม debug tools


docker compose --profile debug up -d





# รัน ทุก profiles


docker compose --profile debug --profile monitoring up -d

Docker Compose กับ Podman Compose ต่างกันยังไง?

Podman Compose เป็น third-party tool ที่พยายามให้ compatible กับ docker-compose.yml แต่ยังไม่ support ทุก feature เท่า Docker Compose V2 เช่น watch mode, profiles บาง option ยังไม่ทำงานถ้าใช้ Podman ผมแนะนำให้ใช้ podman-compose สำหรับ simple setups แต่ถ้า compose file ซับซ้อนอาจจะต้องใช้ Docker แทนหรือใช้ Podman กับ Kubernetes YAML แทน

ทำไม container start แล้ว exit ทันที?

ปัญหานี้ผมเจอบ่อยมากสาเหตุหลักคือ process ใน container ไม่ได้รันแบบ foreground ดู logs ด้วย docker compose logs service_name ก่อนเลยอีกสาเหตุคือ healthcheck fail ทำให้ container ถูก restart วนลูปให้ลอง comment healthcheck ออกก่อนเพื่อ debug และที่พบบ่อยอีกอย่างคือ environment variable ผิดเช่น database password ไม่ตรง

docker compose up กับ docker compose start ต่างกันยังไง?

docker compose up จะสร้าง container ใหม่ (ถ้ายังไม่มี) สร้าง network สร้าง volume แล้ว start ทุกอย่างส่วน docker compose start จะ start container ที่มีอยู่แล้วเท่านั้นไม่สร้างใหม่ในทางปฏิบัติผมใช้ up -d เกือบทุกครั้งเพราะมัน idempotent ถ้า container มีอยู่แล้วก็แค่ start ไม่ได้สร้างใหม่

จะ update image ยังไงโดยไม่ downtime?

ใช้คำสั่ง docker compose pull เพื่อดึง image ใหม่แล้วตามด้วย docker compose up -d Compose จะ recreate เฉพาะ container ที่ image เปลี่ยนช่วง recreate จะมี downtime สั้นๆประมาณ 1-2 วินาทีถ้าต้องการ zero-downtime ต้องใช้ load balancer หน้า container หรือใช้ Docker Swarm / Kubernetes แทน

เนื้อหาเกี่ยวข้อง — บทความที่เกี่ยวข้อง: Immutable OS Fedora CoreOS Performance Tuning

สรุป

Docker Compose เป็นเครื่องมือที่ทุกคนที่ใช้ Docker ต้องรู้จักมันช่วยจัดการ multi-container applications ได้ง่ายดายผ่าน YAML file เดียวตั้งแต่ development จนถึง production สิ่งสำคัญที่ผมอยากเน้นคืออย่าลืมตั้ง health checks, resource limits, logging configuration และ secrets management เพราะสิ่งเหล่านี้คือสิ่งที่แยก development setup กับ production-ready setup ออกจากกัน

Docker Compose ไม่ใช่คู่แข่งของ Kubernetes แต่เป็นเครื่องมือคนละระดับใช้ Compose สำหรับ single-host deployments และ development ใช้ Kubernetes สำหรับ multi-host orchestration ที่ต้องการ auto-scaling เลือกใช้ให้เหมาะกับขนาดของ application

XM Legend · เทรดเดอร์ & ผู้สอน Forex 13 ปี

ผู้ก่อตั้ง SiamCafe ตั้งแต่ปี 1997 · เทรดเดอร์สาย Forex มากกว่า 13 ปี ได้รับการยกย่องเป็น XM Legend · แบ่งปันความรู้ Forex, ไอที, AI และการเทรด จากประสบการณ์จริงในตลาดจริง