Docker Compose จัด Multi-Container อย่างมือโปร 2026 SiamCafe.net | IT Expert Since 1997

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

Docker Compose — จัด Multi-Container อย่างมือโปร 2026
Docker Compose — จัด Multi-Container อย่างมือโปร 2026 - ภาพประกอบบทความ
โดยอ. บอม (SiamCafe Admin) | 28/02/2026 | DevOps | 1,900+ คำ

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

ถ้าคุณเคยรัน 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 ต้องติดตั้งแยก

ติดตั้งบน 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 เท่านั้น

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

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

ปัญหาใหญ่ที่สุดของ 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

# 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 ได้ดีถ้าตั้งค่าถูกต้อง

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 แทน

สรุป

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

แนะนำโดยผู้เชี่ยวชาญ

iCafeForex สอนเทรด Forex ฟรี SiamLancard IT Solutions

🎬 ดูวิดีโอเพิ่มเติม

เรียนรู้ IT, Forex Trading จากประสบการณ์จริง 30 ปี

▶ YouTube @icafefx
👨‍💻

อ. บอมกิตติทัศน์เจริญพนาสิทธิ์

ผู้ก่อตั้ง SiamCafe.net (1997) | IT Expert 30+ ปี | ประสบการณ์ Network, Server, Security, DevOps