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

CI/CD 持續整合部署

什麼是 CI/CD?

💡 比喻:工廠生產線 傳統做法:工人手工組裝每一件產品,品質不穩定,速度慢。 CI/CD:建立自動化生產線,每個步驟都自動檢查,有問題立刻停下來。

  • CI(Continuous Integration)持續整合 = 自動檢查零件品質
  • CD(Continuous Deployment)持續部署 = 自動包裝出貨

CI/CD 流程

開發者推 Code
    ↓
CI 自動觸發
    ├── 1. 還原套件(dotnet restore)
    ├── 2. 編譯(dotnet build)
    ├── 3. 執行測試(dotnet test)
    ├── 4. 程式碼品質檢查
    └── 5. 建置 Docker Image
    ↓
CD 自動部署
    ├── 6. 推送 Image 到 Registry
    ├── 7. 部署到測試環境
    ├── 8. 部署到正式環境
    └── 9. 通知團隊

GitHub Actions 基礎

Workflow 設定檔位置

你的專案/
├── .github/
│   └── workflows/
│       ├── ci.yml        ← CI 工作流程
│       └── deploy.yml    ← 部署工作流程
├── src/
├── tests/
└── Dockerfile

基本 CI Workflow

# .github/workflows/ci.yml
# 工作流程名稱
name: CI Pipeline

# 觸發條件
on:
  # 推送到 main 或 develop 分支時觸發
  push:
    branches: [ main, develop ]
  # Pull Request 到 main 時觸發
  pull_request:
    branches: [ main ]

# 定義工作
jobs:
  # 工作名稱:build-and-test
  build-and-test:
    # 執行環境:最新版 Ubuntu
    runs-on: ubuntu-latest

    # 步驟
    steps:
      # 步驟 1:拉取程式碼
      - name: Checkout code
        uses: actions/checkout@v4

      # 步驟 2:安裝 .NET SDK
      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'

      # 步驟 3:還原 NuGet 套件
      - name: Restore dependencies
        run: dotnet restore

      # 步驟 4:編譯專案
      - name: Build
        run: dotnet build --configuration Release --no-restore

      # 步驟 5:執行單元測試
      - name: Test
        run: dotnet test --configuration Release --no-build --verbosity normal

      # 步驟 6:發佈應用程式
      - name: Publish
        run: dotnet publish --configuration Release --no-build -o ./publish

加入 Docker Build

# .github/workflows/docker.yml
# Docker 建置和推送工作流程
name: Docker Build & Push

on:
  push:
    branches: [ main ]

jobs:
  docker:
    runs-on: ubuntu-latest

    steps:
      # 拉取程式碼
      - name: Checkout
        uses: actions/checkout@v4

      # 登入 Docker Hub
      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          # 從 GitHub Secrets 讀取帳號密碼
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      # 建置並推送 Docker Image
      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          # 標記 Image 名稱和版本
          tags: |
            myapp:latest
            myapp:${{ github.sha }}

Build → Test → Deploy Pipeline

完整的 CI/CD Pipeline

# .github/workflows/pipeline.yml
# 完整的 CI/CD Pipeline
name: Full Pipeline

on:
  push:
    branches: [ main ]

jobs:
  # === 階段 1:Build & Test ===
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'

      # 還原、編譯、測試一氣呵成
      - name: Build and Test
        run: |
          dotnet restore
          dotnet build -c Release --no-restore
          dotnet test -c Release --no-build

      # 上傳建置產物(給下一個 Job 使用)
      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: publish
          path: ./publish/

  # === 階段 2:Deploy to Staging ===
  deploy-staging:
    # 依賴 build 工作完成後才執行
    needs: build
    runs-on: ubuntu-latest
    # 只有 main 分支才部署
    if: github.ref == 'refs/heads/main'
    # 指定環境(GitHub 環境保護規則)
    environment: staging

    steps:
      # 下載上一階段的建置產物
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: publish

      # 部署到 Staging 環境
      - name: Deploy to Staging
        run: echo "部署到測試環境..."

  # === 階段 3:Deploy to Production ===
  deploy-production:
    # 依賴 staging 部署完成
    needs: deploy-staging
    runs-on: ubuntu-latest
    # 需要手動審核的環境
    environment: production

    steps:
      - name: Download artifact
        uses: actions/download-artifact@v4
        with:
          name: publish

      # 部署到正式環境
      - name: Deploy to Production
        run: echo "部署到正式環境..."

Branch 策略

推薦的分支策略:

main(正式環境)
  ↑ merge(需要 PR + Code Review)
develop(開發環境)
  ↑ merge(需要 PR)
feature/add-login(功能分支)

流程:
1. 從 develop 切出 feature 分支
2. 在 feature 分支開發、commit
3. 推上 GitHub,建立 PR 到 develop
4. CI 自動跑測試 ← 測試失敗就不能 merge!
5. Code Review 通過 → merge 到 develop
6. develop 累積足夠功能 → merge 到 main
7. main 自動部署到正式環境
分支命名規範:

feature/add-login        → 新功能
feature/user-profile     → 新功能
bugfix/fix-login-error   → 修 Bug
hotfix/security-patch    → 緊急修復(直接從 main 切)
release/v1.2.0           → 發版準備

GitHub Branch Protection

建議的 Branch Protection 設定:

main 分支:
├── ✅ Require pull request(必須 PR,不能直接 push)
├── ✅ Require approvals(至少 1 人 Code Review)
├── ✅ Require status checks(CI 必須通過)
├── ✅ Require branches to be up to date(必須是最新的)
└── ❌ Allow force push(禁止 force push)

develop 分支:
├── ✅ Require pull request
├── ✅ Require status checks
└── ⬜ Require approvals(可選)

GitHub Secrets 管理

GitHub Secrets 用於存儲機密資料:

設定路徑:
Repository → Settings → Secrets and variables → Actions

常見的 Secrets:
├── DOCKER_USERNAME    → Docker Hub 帳號
├── DOCKER_PASSWORD    → Docker Hub 密碼
├── DEPLOY_KEY         → 部署用的 SSH Key
├── DATABASE_URL       → 資料庫連線字串
└── JWT_SECRET         → JWT 簽章金鑰
# 在 Workflow 中使用 Secrets
env:
  # 用 ${{ secrets.名稱 }} 讀取 Secrets
  DATABASE_URL: ${{ secrets.DATABASE_URL }}

steps:
  - name: Deploy
    # Secrets 不會出現在 Log 中(自動遮罩)
    run: echo "部署中..." && deploy --db $DATABASE_URL

🤔 我這樣寫為什麼會錯?

❌ 錯誤 1:CI 沒有跑測試

# ❌ 錯誤:CI 只有 build,沒有 test
steps:
  - run: dotnet restore
  - run: dotnet build
  # 沒有 dotnet test!
  # 這樣就算程式碼有 Bug,CI 還是會通過

# ✅ 正確:CI 一定要包含測試
steps:
  - run: dotnet restore
  - run: dotnet build -c Release --no-restore
  # 一定要跑測試!測試失敗就停止 Pipeline
  - run: dotnet test -c Release --no-build

❌ 錯誤 2:從本機直接部署

❌ 錯誤流程:
開發者在自己電腦 → dotnet publish → 手動複製到伺服器

問題:
├── 「在我電腦上明明可以跑啊!」(環境不一致)
├── 忘記跑測試就部署了
├── 不知道是誰部署的、部署了什麼版本
└── 無法回滾到上一版

✅ 正確流程:
開發者 push code → GitHub Actions 自動 build + test → 自動部署

好處:
├── 環境一致(都在 CI 的 Ubuntu 上 build)
├── 自動跑測試(測試失敗不會部署)
├── 有完整的部署紀錄
└── 可以隨時回滾

❌ 錯誤 3:把 Secrets 寫在 Workflow 檔案中

# ❌ 錯誤:密碼直接寫在 YAML 中(推上 Git 就洩漏了)
env:
  DOCKER_PASSWORD: "my-real-password-123"

# ✅ 正確:使用 GitHub Secrets
env:
  # ${{ secrets.DOCKER_PASSWORD }} 會從 GitHub Secrets 讀取
  # 而且不會出現在 CI 的 Log 中
  DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}

💡 重點整理

概念 說明
CI(持續整合) 自動 build + test,確保程式碼品質
CD(持續部署) 自動部署到測試/正式環境
GitHub Actions GitHub 內建的 CI/CD 工具
Workflow YAML 格式的自動化流程定義
Branch Protection 保護重要分支,強制 PR 和 Code Review
GitHub Secrets 安全儲存機密資料(密碼、Key)

💡 大家的想法 · 0

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