☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
microservices 中級

🐳 微服務容器化:Docker 與 Docker Compose

📌 每個微服務一個容器

容器化是微服務的最佳搭檔:每個服務打包成獨立的 Docker Image,確保開發、測試、生產環境一致。

微服務容器化架構:
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Product │ │  Order  │ │ Payment │
│ Service │ │ Service │ │ Service │
│ :5002   │ │ :5003   │ │ :5004   │
└────┬────┘ └────┬────┘ └────┬────┘
     │           │           │
     └───────────┼───────────┘
                 │
          ┌──────┴──────┐
          │ API Gateway │
          │    :5000    │
          └─────────────┘

📌 Dockerfile 撰寫:多階段建置

# ── ProductService/Dockerfile ──

# 階段 1:建置 (Build)
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src

# 先複製 csproj 並還原套件(利用 Docker 快取層)
COPY ["ProductService.csproj", "."]
RUN dotnet restore

# 複製所有程式碼並建置
COPY . .
RUN dotnet publish -c Release -o /app/publish --no-restore

# 階段 2:執行 (Runtime) — 用小型映像檔
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS runtime
WORKDIR /app

# 建立非 root 用戶(安全性)
RUN adduser --disabled-password --gecos "" appuser
USER appuser

COPY --from=build /app/publish .

# 健康檢查
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl -f http://localhost:8080/health || exit 1

EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080

ENTRYPOINT ["dotnet", "ProductService.dll"]

.dockerignore

# .dockerignore — 不要把不必要的檔案複製進容器
**/bin/
**/obj/
**/.vs/
**/.git
**/node_modules/
**/*.user
**/*.dbmdl
**/Dockerfile*
**/docker-compose*

📌 Docker Compose 編排多個服務

# docker-compose.yml
version: '3.8'

services:
  # ── API Gateway ──
  api-gateway:
    build:
      context: ./ApiGateway
      dockerfile: Dockerfile
    ports:
      - "5000:8080"
    depends_on:
      product-service:
        condition: service_healthy
      order-service:
        condition: service_healthy
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
    networks:
      - eshop-network

  # ── Product Service ──
  product-service:
    build:
      context: ./ProductService
      dockerfile: Dockerfile
    environment:
      - ConnectionStrings__DefaultConnection=Host=product-db;Database=ProductDb;Username=postgres;Password=postgres123
      - ASPNETCORE_ENVIRONMENT=Development
    depends_on:
      product-db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 15s
    networks:
      - eshop-network

  # ── Order Service ──
  order-service:
    build:
      context: ./OrderService
      dockerfile: Dockerfile
    environment:
      - ConnectionStrings__DefaultConnection=Host=order-db;Database=OrderDb;Username=postgres;Password=postgres123
      - RabbitMq__Host=rabbitmq
      - ASPNETCORE_ENVIRONMENT=Development
    depends_on:
      order-db:
        condition: service_healthy
      rabbitmq:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 10s
      timeout: 5s
      retries: 3
    networks:
      - eshop-network

  # ── Payment Service ──
  payment-service:
    build:
      context: ./PaymentService
      dockerfile: Dockerfile
    environment:
      - ConnectionStrings__DefaultConnection=Host=payment-db;Database=PaymentDb;Username=postgres;Password=postgres123
      - RabbitMq__Host=rabbitmq
    depends_on:
      - payment-db
      - rabbitmq
    networks:
      - eshop-network

  # ── 資料庫 ──
  product-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: ProductDb
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres123
    volumes:
      - product-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - eshop-network

  order-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: OrderDb
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres123
    volumes:
      - order-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks:
      - eshop-network

  payment-db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: PaymentDb
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: postgres123
    volumes:
      - payment-data:/var/lib/postgresql/data
    networks:
      - eshop-network

  # ── 基礎設施 ──
  rabbitmq:
    image: rabbitmq:3-management-alpine
    ports:
      - "15672:15672"  # 管理介面
    environment:
      RABBITMQ_DEFAULT_USER: guest
      RABBITMQ_DEFAULT_PASS: guest
    healthcheck:
      test: ["CMD", "rabbitmq-diagnostics", "check_port_connectivity"]
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - eshop-network

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    networks:
      - eshop-network

volumes:
  product-data:
  order-data:
  payment-data:

networks:
  eshop-network:
    driver: bridge

📌 常用 Docker Compose 指令

# 啟動所有服務(背景執行)
docker compose up -d

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

# 查看特定服務的日誌
docker compose logs -f product-service

# 只重建並重啟某個服務
docker compose up -d --build product-service

# 停止並移除所有容器
docker compose down

# 停止並移除所有容器 + 資料卷(清除資料庫)
docker compose down -v

# 擴展某個服務的實例數量
docker compose up -d --scale product-service=3

📌 環境變數管理

# docker-compose.override.yml(開發環境覆蓋設定)
services:
  product-service:
    environment:
      - ASPNETCORE_ENVIRONMENT=Development
      - Logging__LogLevel__Default=Debug
    ports:
      - "5002:8080"  # 開發時暴露埠口方便偵錯
// Program.cs — 在程式碼中讀取環境變數
var connectionString = builder.Configuration
    .GetConnectionString("DefaultConnection")
    ?? throw new InvalidOperationException("Missing connection string");

var rabbitHost = builder.Configuration["RabbitMq:Host"] ?? "localhost";

📌 服務間網路通訊

# 在 docker-compose 中,服務名稱就是 DNS 名稱
# product-service 可以透過 http://order-service:8080 呼叫 order-service
# 不需要知道實際的 IP 地址

# 自訂網路讓服務隔離
networks:
  eshop-network:
    driver: bridge
  monitoring-network:
    driver: bridge

下一章: 我們將學習微服務的韌性模式,用 Polly 處理網路故障和服務不可用的狀況。

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊