跳至主要內容

Docker Compose 多服務架構設計與實踐

9 分鐘閱讀 1,050 字

Docker Compose 多服務架構設計與實踐

現代應用幾乎都由多個服務組成:Web 伺服器、資料庫、快取、訊息佇列……如何讓這些服務在開發環境中順暢協作,Docker Compose 提供了最直觀的解答。本文將從架構設計的角度,探討如何用 Docker Compose 搭建健壯的多服務環境。

為什麼選擇 Docker Compose

相較於手動管理多個 docker run 命令,Docker Compose 帶來幾個關鍵優勢:

  • 宣告式配置:整個服務棧的定義都在一個 YAML 檔案中,版本可控
  • 自動網路:同一 Compose 檔案中的服務自動加入同一網路,可用服務名互相解析
  • 依賴管理:透過 depends_on 控制啟動順序
  • 環境隔離:不同專案使用獨立的網路命名空間

基礎架構範例

以一個典型的 Web 應用為例,包含 Nginx、Node.js API、PostgreSQL 和 Redis:

# docker-compose.yml
version: "3.9"

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
    depends_on:
      - api
    networks:
      - frontend

  api:
    build:
      context: ./api
      dockerfile: Dockerfile
    environment:
      - NODE_ENV=development
      - DATABASE_URL=postgresql://user:password@postgres:5432/mydb
      - REDIS_URL=redis://redis:6379
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    networks:
      - frontend
      - backend
    volumes:
      - ./api:/app
      - /app/node_modules

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./db/init:/docker-entrypoint-initdb.d:ro
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d mydb"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - backend

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes --requirepass redispassword
    volumes:
      - redis_data:/data
    networks:
      - backend

networks:
  frontend:
  backend:
    internal: true  # 後端網路不對外暴露

volumes:
  postgres_data:
  redis_data:

健康檢查與啟動依賴

depends_oncondition 選項是 Compose v3 的重要功能,讓你能確保服務在依賴真正就緒後才啟動:

depends_on:
  postgres:
    condition: service_healthy  # 等待 healthcheck 通過
  redis:
    condition: service_started  # 只等容器啟動
  migrations:
    condition: service_completed_successfully  # 等待一次性任務完成

搭配健康檢查,可以有效避免「資料庫還在初始化,API 就已經崩潰」的問題。

多環境配置策略

實務中通常需要區分開發、測試、正式環境。推薦使用 override 檔案模式:

docker-compose.yml          # 基礎配置(共用部分)
docker-compose.dev.yml      # 開發環境覆蓋
docker-compose.prod.yml     # 正式環境覆蓋
docker-compose.test.yml     # 測試環境覆蓋
# docker-compose.dev.yml
services:
  api:
    command: npm run dev  # 使用 nodemon 熱重載
    environment:
      - DEBUG=*
    ports:
      - "9229:9229"  # Node.js 偵錯埠

  postgres:
    ports:
      - "5432:5432"  # 開發時開放埠,方便 GUI 工具連接

啟動命令:

# 開發環境
docker compose -f docker-compose.yml -f docker-compose.dev.yml up

# 正式環境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

管理機密資訊

永遠不要把密碼硬寫在 docker-compose.yml 中。使用 .env 檔案或 Docker Secrets:

# .env
POSTGRES_PASSWORD=supersecretpassword
REDIS_PASSWORD=anotherpassword
JWT_SECRET=myjwtsecret
# docker-compose.yml
services:
  postgres:
    environment:
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

記得將 .env 加入 .gitignore,並提供 .env.example 範本給團隊成員。

資料持久化策略

volumes:
  # 具名 Volume:由 Docker 管理,適合資料庫等需要持久化的資料
  postgres_data:
    driver: local
  
  # Bind Mount:直接掛載主機目錄,適合開發時的程式碼熱重載
  # - ./src:/app/src

  # tmpfs:僅存記憶體,適合測試環境的暫存資料
  # tmpfs: /tmp

常用除錯命令

# 查看所有服務狀態
docker compose ps

# 即時查看日誌(多服務)
docker compose logs -f api postgres

# 在執行中的容器執行命令
docker compose exec api sh
docker compose exec postgres psql -U user -d mydb

# 重建特定服務映像
docker compose build --no-cache api

# 清理所有資源
docker compose down -v --remove-orphans

效能調優

在開發環境中,Volume 掛載可能成為效能瓶頸(尤其在 macOS 上)。可以使用以下技巧:

services:
  api:
    volumes:
      - ./src:/app/src:cached   # 讀取優先,適合主機寫入、容器讀取
      - /app/node_modules        # 匿名 Volume,避免掛載 node_modules

總結

Docker Compose 讓多服務架構的管理變得簡單可控。關鍵要點:善用健康檢查確保啟動順序、用 override 檔案分離環境配置、妥善管理機密資訊,以及設計合理的網路隔離策略。掌握這些技巧,能讓你的本地開發環境與正式環境保持高度一致性。

分享這篇文章