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 的核心價值

  1. 單指令啟動docker compose up -d 一次啟動所有服務
  2. 自動網路管理:所有服務自動加入同一個虛擬網路,可以透過服務名稱互相溝通
  3. 依賴管理:可以設定 depends_on 確保啟動順序
  4. 環境統一:整個團隊使用同一份 Compose 設定,保證開發環境一致
  5. 資源限制:可以為每個服務設定 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 建置 Image
  • depends_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 策略。」

本日總結

在本章中,你學到了:

  1. Docker Compose 的核心概念:解決多容器管理的痛點
  2. compose.yaml 設定語法:定義服務、網路、Volume 與環境變數
  3. 三層式架構實戰:PostgreSQL + FastAPI + Next.js 的完整範例
  4. 啟動與管理:up、down、logs、exec 等關鍵指令
  5. 環境變數管理:使用 .env 檔案分離設定與程式碼
  6. Vibe Coding 生成技巧:用自然語言描述,讓 AI 幫你產出 Compose 設定

下一章,我們將正式進入 Kubernetes 的世界,學習如何管理大規模的容器叢集!

解鎖完整教學內容

本章為付費內容。加入專案即可解鎖超過 5000 字的深度解析,包含 10 個以上神級 Prompt 與真實 Source Code 範例!