ข้ามไปยังเนื้อหา

ไฟล์ compose.yaml

ทุก Compose file มี key ระดับบนสุดที่จำเป็นหนึ่งตัว: services ส่วนอื่นๆ — networks, volumes, configs — เป็นตัวเลือก

services:
service-name:
image: some-image:tag
build: .
ports:
- "hostPort:containerPort"
environment:
- KEY=value
command: ["executable", "arg"]

แต่ละ key ภายใต้ services คือชื่อ service ที่คุณเลือกเอง Compose สตาร์ทหนึ่ง container ต่อหนึ่ง service โดยค่าเริ่มต้น

services คือ map แต่ละรายการคือ service ที่มีชื่อ ชื่อนั้นกลายเป็นทั้ง identifier ของ container และ DNS hostname ที่ service อื่นใช้เข้าถึง service นั้นบน network ภายใน

services:
api:
image: node:22-alpine
db:
image: postgres:17-alpine

ที่นี่ api และ db คือสอง service Compose สร้างหนึ่ง container สำหรับแต่ละตัว

ใช้ image เพื่อ pull image สำเร็จรูปจาก registry:

services:
web:
image: nginx:alpine

ใช้ build เพื่อสร้าง image จาก Dockerfile ในเครื่องตอน build time:

services:
app:
build: .

คุณสามารถรวมทั้งสองได้ — build บอกว่า Dockerfile อยู่ที่ไหน และ image ตั้งชื่อ image ที่ได้:

services:
app:
build: .
image: myapp:dev

ports map host port ไปยัง container port ในรูปแบบ "host:container" ใส่ quote เสมอเพื่อป้องกัน YAML แปลค่าผิด:

services:
web:
image: nginx:alpine
ports:
- "8080:80"
- "8443:443"

ส่ง environment variables เข้า container แบบ list หรือ mapping:

# แบบ list
environment:
- NODE_ENV=production
- PORT=3000
# แบบ mapping
environment:
NODE_ENV: production
PORT: "3000"

ทั้งสองแบบเทียบเท่ากัน แบบ list คล้าย shell export syntax จึงพบบ่อยกว่า

Override ค่า CMD เริ่มต้นจาก image:

services:
worker:
image: myapp:latest
command: ["node", "worker.js"]

ส่งเป็น string ธรรมดาสำหรับคำสั่งที่ให้ shell ตีความ:

services:
worker:
image: myapp:latest
command: node worker.js

tutorial เก่าๆ จะแสดง version: "3.9" ที่ด้านบนของไฟล์ นั่นล้าสมัยแล้ว Compose Specification ไม่ต้องการหรือแนะนำ key version อีกต่อไป tooling รุ่นใหม่ไม่สนใจ key นี้แล้ว ไฟล์ใหม่ไม่ต้องใส่เลย

services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://db:5432/mydb
command: ["node", "src/server.js"]
db:
image: postgres:17-alpine
environment:
- POSTGRES_PASSWORD=secret

snippet ด้านล่างเขียน compose.yaml สมบูรณ์และสตาร์ทเพื่อตรวจสอบแต่ละ field ในทางปฏิบัติ

# Write a compose.yaml with two services
cat > compose.yaml <<'EOF'
services:
  web:
    image: nginx:alpine
    ports:
      - "8080:80"
    environment:
      - NGINX_HOST=localhost
    command: ["nginx", "-g", "daemon off;"]
  echo:
    image: alpine
    command: ["sh", "-c", "echo 'compose.yaml works!' && sleep 30"]
EOF

# Start both services
docker compose up -d

# Show running containers
docker compose ps

# Read echo output
docker compose logs echo

# Clean up
docker compose down
ตัวเลือกBenefitCost
Docker Composeเขียน compose.yaml ไฟล์เดียว รัน local ได้ทันที เหมาะกับ dev loopรันได้จริงบน host เดียว ไม่มี self-healing ข้าม node
Kubernetesscale และ self-heal ข้ามหลาย node ในคลัสเตอร์ต้องเรียนรู้ manifest, controller และ operational overhead ที่สูงกว่ามาก
  • ลืมว่า key services เป็น required key เดียว แล้วพยายามใส่ config ระดับ service ไว้ผิดที่ (เช่นใส่ image:ไว้นอก block ของ service)
  • ใส่ version: "3.9" กลับเข้ามาใน compose.yaml ใหม่เพราะ copy จาก tutorial เก่า ทั้งที่ tooling ปัจจุบันไม่อ่านค่านี้แล้ว
  • ลืมใส่ quote รอบ port mapping (เช่น ports: - 8080:80 แทนที่จะเป็น "8080:80") ทำให้ YAML parser ตีความ colon ผิดในบางเคส

💡 ตัวอย่างจากของจริง

ทีม dev ที่ Shopify และทีมเล็กจำนวนมากใช้ compose.yaml เดียวกันเป็นจุดเริ่มต้นของทั้ง local dev และ production image — เขียนโครงสร้าง services ให้ถูกต้องตั้งแต่ compose-file แล้วค่อยเอา image เดียวกันไป deploy บน Kubernetes ทีหลัง

key ระดับบนสุดใดที่จำเป็นในทุก compose.yaml?
วิธีที่ถูกต้องในการ map host port 9000 ไปยัง container port 80 ใน compose.yaml คืออะไร?
ทำไมต้องละเว้น key version: จากไฟล์ compose.yaml ใหม่?
key build: . ในนิยาม service ทำอะไร?