Docker Compose:多服務協作管理
在真實的商業專案中,幾乎沒有任何應用是孤立的。一個現代化的 SaaS 系統通常由多個服務組成:
- 前端服務:Next.js / React App
- 後端 API:FastAPI / Express.js
- 資料庫:PostgreSQL / MySQL
- 快取層:Redis
- 任務佇列:RabbitMQ / Bull Queue
- 排程爬蟲:Python Scraper
如果我們每次都用手動指令一個一個啟動這些容器,不僅非常麻煩,而且容易搞錯啟動順序(資料庫必須先啟動,應用才能連線)。
Docker Compose 就是為了解決這個問題而生的工具!
什麼是 Docker Compose?
Docker Compose 是一個用來定義與運行多容器 Docker 應用的工具。你只需要寫一個 compose.yaml (或 docker-compose.yml) 檔案,在其中描述你的服務架構,然後一個指令就可以啟動整個系統。
Compose 的核心價值
- 單指令啟動:
docker compose up -d一次啟動所有服務 - 自動網路管理:所有服務自動加入同一個虛擬網路,可以透過服務名稱互相溝通
- 依賴管理:可以設定 depends_on 確保啟動順序
- 環境統一:整個團隊使用同一份 Compose 設定,保證開發環境一致
- 資源限制:可以為每個服務設定 CPU、記憶體上限
實戰:建立一個三層式應用架構
現在,我們要建立一個完整的範例:一個具有 PostgreSQL 資料庫 + FastAPI 後端 + Next.js 前端的標準三層式應用。
專案結構
my-fullstack-app/
├── frontend/ # Next.js 應用
│ ├── package.json
│ ├── Dockerfile
│ └── ...
├── backend/ # FastAPI 應用
│ ├── main.py
│ ├── requirements.txt
│ ├── Dockerfile
│ └── ...
├── docker-compose.yml # 核心:Compose 設定檔
└── .env # 環境變數
第一步:建立 docker-compose.yml
在專案根目錄建立 docker-compose.yml:
version: "3.8"
services:
# === 資料庫服務 ===
postgres:
image: postgres:16-alpine
container_name: myapp-postgres
restart: unless-stopped
environment:
POSTGRES_USER: ${DB_USER:-myapp}
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret123}
POSTGRES_DB: ${DB_NAME:-myapp}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
- ./backend/init.sql:/docker-entrypoint-initdb.d/init.sql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U myapp"]
interval: 10s
timeout: 5s
retries: 5
# === 後端 API 服務 ===
backend:
build:
context: ./backend
dockerfile: Dockerfile
container_name: myapp-backend
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
environment:
DATABASE_URL: postgresql://${DB_USER:-myapp}:${DB_PASSWORD:-secret123}@postgres:5432/${DB_NAME:-myapp}
API_PORT: 8000
ports:
- "8000:8000"
volumes:
- ./backend:/app
command: uvicorn main:app --host 0.0.0.0 --port 8000 --reload
# === 前端服務 ===
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
container_name: myapp-frontend
restart: unless-stopped
depends_on:
- backend
environment:
NEXT_PUBLIC_API_URL: http://backend:8000
DATABASE_URL: postgresql://${DB_USER:-myapp}:${DB_PASSWORD:-secret123}@postgres:5432/${DB_NAME:-myapp}
ports:
- "3000:3000"
volumes:
- ./frontend:/app
- /app/node_modules
- /app/.next
volumes:
postgres_data:
YAML 設定解析
讓我們逐一解讀這個 Compose 檔案的每個部分:
頂層結構:
services:定義所有服務(容器)volumes:定義持久化儲存空間(資料庫的資料不能隨著容器刪除而消失)
postgres 服務:
image: postgres:16-alpine:直接使用官方 Image,不須自行建置restart: unless-stopped:除非手動停止,否則自動重新啟動environment:設定資料庫的使用者、密碼與資料庫名稱volumes:將資料庫檔案儲存在命名卷 (named volume) 中,容器刪除後資料不流失healthcheck:定期檢查資料庫是否就緒
backend 服務:
build:指定從./backend/目錄中的 Dockerfile 建置 Imagedepends_on:等到 postgres 的健康檢查通過後才啟動environment:資料庫連線字串使用了postgres作為主機名稱(因為 Docker Compose 會自動建立 DNS 解析)
frontend 服務:
- 同樣依賴後端
- 使用了匿名卷技巧 (
/app/node_modules) 來避免 Host 與 Container 的 node_modules 衝突
啟動與管理多容器環境
啟動所有服務
# 在 docker-compose.yml 所在的目錄執行
docker compose up -d
-d 表示背景執行。執行後,你會看到 Docker Compose 依序建立網路、建置 Image 並啟動容器:
[+] Running 4/4
✔ Network my-fullstack-app_default Created
✔ Volume my-fullstack-app_postgres_data Created
✔ Container myapp-postgres Started
✔ Container myapp-backend Started
✔ Container myapp-frontend Started
查看服務狀態
# 查看所有正在運行的服務
docker compose ps
# 查看即時日誌(所有服務)
docker compose logs -f
# 查看特定服務的日誌
docker compose logs -f backend
執行單次指令
如果你需要對某個服務執行一次性的指令,例如執行資料庫 migration:
# 在 backend 容器中執行 alembic migration
docker compose exec backend alembic upgrade head
# 連線到資料庫查看資料
docker compose exec postgres psql -U myapp -d myapp -c "SELECT * FROM users;"
重新建置特定服務
當你修改了某個服務的程式碼或 Dockerfile,需要重新建置:
# 只重新建置並啟動 backend
docker compose up -d --build backend
# 重新建置所有服務
docker compose up -d --build
停止與清除
# 停止所有服務(不刪除容器與卷)
docker compose stop
# 停止並刪除所有容器與網路
docker compose down
# 完全清除(連同資料庫卷一起刪除!小心使用)
docker compose down -v
⚠️ 重要提醒:
down -v會刪除所有 Volume,包含資料庫的資料。只有在確定要完全重置環境時才使用這個指令。
環境變數管理(.env 檔案)
在上面的 Compose 設定中,我們使用了 ${DB_USER:-myapp} 這樣的語法。這代表 Docker Compose 會從 .env 檔案中讀取變數,如果沒有設定則使用預設值 myapp。
在專案根目錄建立 .env 檔案:
# .env
DB_USER=myapp
DB_PASSWORD=your_strong_password_here
DB_NAME=myapp
為什麼要使用 .env?
- 避免在 Compose 檔案中寫死密碼
- 可以針對不同環境(開發/測試/正式)使用不同的
.env檔案 - 將
.env加入.gitignore,避免機敏資料外洩
使用 Vibe Coding 生成 Compose 設定
如果你不想手寫這些 YAML,可以請 AI 幫你產生:
**🔥 【Docker Compose 詠唱範例】 **
「請幫我寫一個 docker-compose.yml,包含以下服務:1. PostgreSQL 16,使用者為 myapp,密碼從 .env 讀取。資料存在 volume 中。2. Redis 7 作為快取層。3. Node.js 後端 API(Express.js),連線到 postgres 與 redis。需要支援熱重載 (nodemon)。4. Next.js 前端,連線到後端 API。5. 所有服務必須有依賴順序。後端要等到 postgres 健康檢查通過再啟動。6. 請加上 healthcheck 與 restart 策略。」
本日總結
在本章中,你學到了:
- ✅ Docker Compose 的核心概念:解決多容器管理的痛點
- ✅ compose.yaml 設定語法:定義服務、網路、Volume 與環境變數
- ✅ 三層式架構實戰:PostgreSQL + FastAPI + Next.js 的完整範例
- ✅ 啟動與管理:up、down、logs、exec 等關鍵指令
- ✅ 環境變數管理:使用 .env 檔案分離設定與程式碼
- ✅ Vibe Coding 生成技巧:用自然語言描述,讓 AI 幫你產出 Compose 設定
下一章,我們將正式進入 Kubernetes 的世界,學習如何管理大規模的容器叢集!