สารบัญ
- Docker Compose คืออะไร ทำไมต้องใช้?
- ติดตั้ง Docker Engine และ Docker Compose บน Ubuntu
- โครงสร้างไฟล์ docker-compose.yml
- ตัวอย่าง: WordPress + MySQL + phpMyAdmin
- ตัวอย่าง: Node.js + PostgreSQL + Redis
- คำสั่ง Docker Compose ที่ใช้บ่อย
- Network และ Volume ใน Docker Compose
- ใช้ .env file จัดการ Secret อย่างปลอดภัย
- เทคนิค Production-ready
- แก้ปัญหาที่พบบ่อย
- คำถามที่พบบ่อย (FAQ)
Docker Compose คืออะไร ทำไมต้องใช้?
แอปพลิเคชันสมัยใหม่ไม่ได้รันใน container เดียว — ระบบ e-commerce ปกติต้องการ web server, database, cache, queue worker และ reverse proxy ทำงานร่วมกัน Docker Compose คือเครื่องมือที่ช่วยจัดการ multi-container application ทั้งหมดผ่านไฟล์ YAML ไฟล์เดียว
| ด้าน | Docker (docker run) | Docker Compose |
|---|---|---|
| จำนวน container | ทีละตัว | หลาย service พร้อมกัน |
| Network | สร้างเอง | สร้างอัตโนมัติ |
| Volume | ระบุใน flag | นิยามใน YAML |
| Dependency | จัดการเอง | depends_on + healthcheck |
| Restart | ตั้ง flag ทีละตัว | restart policy ใน YAML |
Docker Compose เหมาะสำหรับ development environment และ small-to-medium production บน VPS เดี่ยว ถ้าต้องการ scale หลาย server ข้ามไปดู Docker Swarm หรือ Kubernetes แทน
ติดตั้ง Docker Engine และ Docker Compose บน Ubuntu
แนะนำ Ubuntu 22.04 LTS หรือ 24.04 LTS สำหรับ production
ขั้นตอนที่ 1 — อัปเดต package และติดตั้ง dependency
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl gnupg lsb-release
ขั้นตอนที่ 2 — เพิ่ม Docker GPG key และ repository
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
ขั้นตอนที่ 3 — ติดตั้ง Docker Engine และ Compose Plugin
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io \
docker-buildx-plugin docker-compose-plugin
ขั้นตอนที่ 4 — ให้ user ใช้ Docker โดยไม่ต้อง sudo
sudo usermod -aG docker $USER
newgrp docker # หรือ logout แล้ว login ใหม่
ตรวจสอบการติดตั้ง
docker --version # Docker version 26.x.x
docker compose version # Docker Compose version v2.x.x
docker compose (ไม่มี hyphen) แทน docker-compose (มี hyphen) ในเวอร์ชันเก่า บทความนี้ใช้ v2 ทั้งหมด
โครงสร้างไฟล์ docker-compose.yml
ไฟล์ docker-compose.yml ใช้ YAML syntax นิยาม service, network และ volume ดังนี้
services: # รายการ service/container
web: # ชื่อ service (ใช้เป็น hostname ใน network ได้)
image: nginx:alpine
ports:
- "80:80" # host_port:container_port
volumes:
- ./html:/usr/share/nginx/html:ro
depends_on:
- app
restart: unless-stopped
app:
build: . # build จาก Dockerfile ในโฟลเดอร์ปัจจุบัน
environment:
- NODE_ENV=production
env_file:
- .env
restart: unless-stopped
db:
image: postgres:16-alpine
volumes:
- pgdata:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
restart: unless-stopped
volumes: # named volumes (persistent)
pgdata:
networks: # custom networks (optional — default network สร้างอัตโนมัติ)
default:
driver: bridge
ตัวอย่าง: WordPress + MySQL + phpMyAdmin
สร้างโฟลเดอร์และ compose file:
mkdir ~/wordpress-stack && cd ~/wordpress-stack
# docker-compose.yml
services:
wordpress:
image: wordpress:6.7-php8.2-apache
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_NAME: ${MYSQL_DATABASE}
WORDPRESS_DB_USER: ${MYSQL_USER}
WORDPRESS_DB_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- wp_data:/var/www/html
depends_on:
mysql:
condition: service_healthy
restart: unless-stopped
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
phpmyadmin:
image: phpmyadmin:5-apache
ports:
- "8081:80"
environment:
PMA_HOST: mysql
PMA_PORT: 3306
depends_on:
- mysql
restart: unless-stopped
volumes:
wp_data:
mysql_data:
# .env (สร้างแยกต่างหาก — ห้าม commit ขึ้น Git)
MYSQL_ROOT_PASSWORD=StrongRootPass2026!
MYSQL_DATABASE=wordpress_db
MYSQL_USER=wpuser
MYSQL_PASSWORD=StrongUserPass2026!
# รัน stack
docker compose up -d
# ตรวจสอบ container ทั้งหมดรันอยู่
docker compose ps
ตัวอย่าง: Node.js + PostgreSQL + Redis
mkdir ~/nodeapp-stack && cd ~/nodeapp-stack
# docker-compose.yml
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB}
REDIS_URL: redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
restart: unless-stopped
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- pg_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
command: redis-server --save 20 1 --loglevel warning
volumes:
- redis_data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
volumes:
pg_data:
redis_data:
คำสั่ง Docker Compose ที่ใช้บ่อย
| คำสั่ง | ความหมาย |
|---|---|
docker compose up -d | รัน stack ใน background (detach) |
docker compose down | หยุดและลบ container (volume ยังอยู่) |
docker compose down -v | หยุดและลบทั้ง container + volume |
docker compose ps | ดูสถานะ container ทั้งหมด |
docker compose logs -f | ดู log แบบ real-time |
docker compose logs -f web | ดู log เฉพาะ service "web" |
docker compose exec app sh | เข้า shell ใน container "app" |
docker compose restart | restart ทุก service |
docker compose pull | ดึง image เวอร์ชันใหม่ |
docker compose build | build image จาก Dockerfile ใหม่ |
docker compose config | ตรวจสอบ syntax ของ compose file |
Network และ Volume ใน Docker Compose
Network
Docker Compose สร้าง default network ให้อัตโนมัติ — ทุก service ในไฟล์เดียวกันสามารถเชื่อมหากันผ่าน ชื่อ service ได้เลย เช่น mysql, redis, postgres
# service "app" เชื่อม postgres โดยใช้ hostname "postgres"
DATABASE_URL=postgresql://user:pass@postgres:5432/mydb
# ^^^^^^^ ชื่อ service
Volume
มี 2 ประเภทหลัก:
- Named volume (
pg_data:/var/lib/postgresql/data) — Docker จัดการ, persistent, แนะนำสำหรับ database - Bind mount (
./src:/app/src) — map โฟลเดอร์ host เข้า container, ดีสำหรับ development
ใช้ .env file จัดการ Secret อย่างปลอดภัย
Docker Compose โหลดไฟล์ .env ใน directory เดียวกันอัตโนมัติ ค่าตัวแปรสามารถใช้ใน compose file ผ่าน ${VARIABLE_NAME}
# .env
DB_PASSWORD=MySecurePassword2026
JWT_SECRET=long-random-string-here
REDIS_PASSWORD=RedisPass2026
# .gitignore — ห้าม commit .env เด็ดขาด!
.env
*.env
!.env.example
.env.example ที่มีชื่อ variable แต่ไม่มีค่าจริง เพื่อให้ developer คนอื่นรู้ว่าต้องกำหนดค่าอะไรบ้าง
เทคนิค Production-ready
1. Restart Policy
restart: unless-stopped # รีสตาร์ทเองเสมอ ยกเว้น docker compose stop
2. Resource Limits
services:
app:
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
reservations:
memory: 256M
3. Healthcheck
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
4. Nginx Reverse Proxy
แนะนำให้รัน Nginx ข้างนอก Docker Compose หรือเป็น service แยกใน stack ทำหน้าที่ reverse proxy และจัดการ SSL certificate (Let's Encrypt ผ่าน Certbot)
5. Backup Volume
# backup named volume
docker run --rm \
-v wordpress-stack_mysql_data:/data \
-v $(pwd)/backup:/backup \
alpine tar czf /backup/mysql-$(date +%Y%m%d).tar.gz /data
แก้ปัญหาที่พบบ่อย
| ปัญหา | สาเหตุ | วิธีแก้ |
|---|---|---|
| Container หยุดทันทีหลัง up | Error ใน entrypoint หรือ healthcheck fail | docker compose logs <service> ดู error |
| Port already in use | Port ซ้ำกับ process อื่น | sudo ss -tlnp | grep PORT หาตัวที่ใช้อยู่ |
| Volume data หาย | ใช้ down -v โดยไม่ตั้งใจ | ตรวจสอบ backup ก่อน docker compose down |
| Service เชื่อมกันไม่ได้ | ไม่ได้อยู่ network เดียวกัน | ตรวจสอบ network ใน docker compose config |
| Permission denied บน volume | UID/GID ใน container ไม่ตรง | เพิ่ม user: "UID:GID" ใน service |
คำถามที่พบบ่อย (FAQ)
restart: unless-stopped ใน docker-compose.yml ทุก service Docker Engine จะ restart container อัตโนมัติเมื่อ system boot ขึ้นมาdocker compose pull เพื่อดึง image ใหม่ แล้วรัน docker compose up -d เพื่อ recreate container ด้วย image ใหม่ service ที่ไม่มีการเปลี่ยนแปลงจะไม่ถูก restartสรุป
Docker Compose ช่วยจัดการ multi-container application บน VPS ได้อย่างมีระเบียบ ขั้นตอนหลักคือ ติดตั้ง Docker Engine + Compose Plugin, สร้าง docker-compose.yml นิยาม service, เก็บ secret ใน .env file และเพิ่ม restart policy ให้ container กลับมาทำงานเองหลัง reboot
สำหรับ VPS ที่เหมาะกับ Docker Compose แนะนำ RAM 2-4GB ขึ้นไป AsiaGB มี VPS ไทยและสิงคโปร์ พร้อม SSD รวดเร็ว Uptime 99% เริ่มต้นราคาคุ้มค่า