結論先講
很多團隊的 CI/CD 長這樣:lint → test → build → deploy。看起來有模有樣,但真的出事的時候才發現沒有 rollback、沒有 canary、secrets 是寫死的、build 要跑 20 分鐘。
好的 CI/CD pipeline 不只是「自動化部署」,它是你的品質守門員和安全網。這篇列出 11 個檢查點,幫你評估你的 pipeline 夠不夠成熟。
體檢清單
1. 標準 Pipeline 階段
一個合格的 pipeline 至少要有這些階段:
┌──────┐ ┌──────┐ ┌───────┐ ┌────────┐ ┌────────┐
│ Lint │ → │ Test │ → │ Build │ → │ Deploy │ → │ Verify │
│ │ │ │ │ │ │Staging │ │ │
└──────┘ └──────┘ └───────┘ └────────┘ └────────┘
│
┌────────┐
│ Deploy │
│ Prod │
└────────┘
# GitHub Actions 完整範例
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm run lint
- run: npm run type-check
test:
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
ports: ['5432:5432']
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:coverage
- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
deploy-staging:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment: staging
steps:
- run: echo "Deploy to staging..."
deploy-production:
runs-on: ubuntu-latest
needs: deploy-staging
if: github.ref == 'refs/heads/main'
environment:
name: production
url: https://myapp.com
steps:
- run: echo "Deploy to production..."- Lint(ESLint、Prettier、stylelint)
- Type check(
tsc --noEmit) - Unit test + coverage
- Build
- Deploy to staging
- Deploy to production(需要 approval)
2. 環境隔離
| 環境 | 觸發條件 | 用途 |
|---|---|---|
| Preview | 每個 PR | 讓 reviewer 看實際效果 |
| Development | push to develop | 開發團隊測試 |
| Staging | push to main | QA 驗收、與 production 同等環境 |
| Production | manual approval 或 tag | 真正的使用者 |
- 每個環境有獨立的設定和資料庫
- PR 有 preview deployment
- Staging 環境盡量跟 production 一致
3. Rollback 策略
部署失敗不可怕,可怕的是回不去。
# Docker image rollback
kubectl set image deployment/web web=myapp:v1.2.3 # 部署新版
kubectl rollout undo deployment/web # 回滾
# 或者直接部署舊版
kubectl set image deployment/web web=myapp:v1.2.2- 可以在 5 分鐘內回滾到上一版
- 保留最近 N 個版本的 artifact
- 資料庫 migration 有 backward compatibility
- Rollback 有文件化的 SOP
4. Feature Flags
Feature flag 讓你可以部署程式碼但不啟用功能。
// 使用 feature flag
if (featureFlags.isEnabled('new-checkout-flow', { userId })) {
return <NewCheckoutPage />;
} else {
return <OldCheckoutPage />;
}| 工具 | 特色 |
|---|---|
| LaunchDarkly | 功能最完整、有 targeting |
| Unleash | 開源、可自架 |
| Flagsmith | 開源、有 SaaS |
| 自己做 | 簡單 JSON config |
- 大功能用 feature flag 控制
- 可以針對特定使用者開啟(gradual rollout)
- 舊的 flag 有定期清理
5. Canary / Blue-Green Deployment
Blue-Green:
┌──────────┐ ┌──────────┐
│ Blue │ │ Green │
│ (v1.0) │ ←── │ (v1.1) │ ← 新版部署到 Green
│ Active │ │ Standby │
└──────────┘ └──────────┘
↓ 切換流量
┌──────────┐ ┌──────────┐
│ Blue │ │ Green │
│ (v1.0) │ │ (v1.1) │
│ Standby │ │ Active │ ← 流量切到 Green
└──────────┘ └──────────┘
Canary:
┌──────────┐
│ v1.0 │ ← 95% 流量
│ (穩定) │
└──────────┘
┌──────────┐
│ v1.1 │ ← 5% 流量(金絲雀)
│ (新版) │ ↓ 觀察 metrics,沒問題就逐步增加
└──────────┘
| 策略 | 優點 | 缺點 |
|---|---|---|
| 直接部署 | 簡單 | 失敗影響所有使用者 |
| Blue-Green | 切換快、回滾即時 | 需要雙倍資源 |
| Canary | 風險最小 | 實作複雜 |
| Rolling | 不需額外資源 | 新舊版本共存期間 |
- Production 不用「直接覆蓋」的方式部署
- 至少有 rolling update
- 理想情況用 canary + 自動回滾
6. Secrets Injection
# GitHub Actions secrets
steps:
- run: npm run deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
API_KEY: ${{ secrets.API_KEY }}
# 不好:secrets 寫在 yaml 裡
# 不好:secrets 透過 echo 印出來(會出現在 log 裡)- Secrets 用 CI/CD 平台的 secret store
- 不同環境用不同 secrets
- Secrets 不會出現在 build log 裡
- 有 secrets rotation 機制
7. Artifact Management
- Build output 存成 artifact
- Docker image 推到 registry(ECR、GCR、Docker Hub)
- Image 有 tagging 策略(git SHA + semver)
- 有清理舊 artifact 的機制
# Docker image tagging
docker build -t myapp:${GIT_SHA} -t myapp:v1.2.3 -t myapp:latest .
docker push myapp:${GIT_SHA}
docker push myapp:v1.2.38. 通知
- Build 失敗有通知(Slack、Discord、Email)
- 部署成功/失敗有通知
- 通知包含必要資訊(commit、author、link)
# Slack 通知
- uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Deploy ${{ github.sha }} to production: ${{ job.status }}"
}9. Build Cache
Pipeline 跑 20 分鐘是不能接受的。
# Node modules cache
- uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
# Docker layer cache
- uses: docker/build-push-action@v5
with:
cache-from: type=gha
cache-to: type=gha,mode=max- 依賴套件有 cache
- Docker build 有 layer cache
- CI 總時間 < 10 分鐘(理想 < 5 分鐘)
10. Parallel Execution
# 平行執行 lint 和 test
jobs:
lint:
runs-on: ubuntu-latest
# ...
test-unit:
runs-on: ubuntu-latest
# ...
test-e2e:
runs-on: ubuntu-latest
# ...
build:
needs: [lint, test-unit, test-e2e] # 等所有平行任務完成
# ...- 獨立的 job 平行跑
- Test suite 可以 shard(分散到多台機器)
- 有分析 pipeline bottleneck
11. Branch Protection
-
main分支有保護(不能直接 push) - PR 必須通過 CI 才能合併
- PR 需要至少一個 review
- Force push 被禁止
CI/CD 平台比較
| 平台 | 優點 | 缺點 | 適合 |
|---|---|---|---|
| GitHub Actions | 整合好、marketplace 豐富 | 大量使用可能貴 | GitHub 用戶 |
| GitLab CI | 功能完整、可自架 | 設定較複雜 | GitLab 用戶 |
| CircleCI | 快、UX 好 | 免費額度少 | 中大型團隊 |
| Jenkins | 超高彈性 | 維護成本高、UI 古老 | 企業、特殊需求 |
| Buildkite | 可自架 runner | 需要管理 agent | 大型團隊 |
Pipeline 成熟度
| 等級 | 描述 |
|---|---|
| L0 | 手動部署,沒有 CI |
| L1 | 有 CI(lint + test),手動 deploy |
| L2 | CI + CD(自動部署到 staging) |
| L3 | 全自動 + rollback + feature flags |
| L4 | Canary + 自動回滾 + metrics-based deploy |
FAQ
Q1: CI 跑太慢怎麼辦?
三個方向:cache(npm、Docker layer)、parallel(lint 和 test 同時跑)、shard(把 test 分散到多台)。還可以考慮只跑受影響的 test(affected test detection)。
Q2: 要不要 CD 到 production?
看你的團隊和產品。如果有完善的 test、feature flag、canary,全自動 CD 是可行的。如果 test 覆蓋率低或產品容錯率低(金融、醫療),在 production 前加個 manual approval 比較安全。
Q3: Feature flag 會不會變成技術債?
會。所以要有紀律地清理已經全量上線的 flag。建議設定一個規則:feature 上線兩週後,如果沒有要回滾,就清掉 flag。
Q4: Monorepo 的 CI 怎麼做?
用 affected detection。Nx、Turborepo 都有內建功能,只跑被改到的 package 的 CI。不然每次改一行字就跑全部 package 的 test,CI 時間會爆炸。
Q5: 自架 runner 還是用平台的?
小團隊用平台的就好(GitHub Actions runners)。如果你有特殊硬體需求(GPU、ARM)、安全合規要求、或 CI 用量很大,再考慮自架。
系列導航
| # | 文章 | 狀態 |
|---|---|---|
| 01 | 好的前端專案該有什麼?一張體檢表 | |
| 02 | 好的後端框架需要具備哪些功能? | |
| 03 | 好的 API 該長什麼樣? | |
| 04 | 好的資料庫設計需要什麼? | |
| 05 | 好的基礎建設需要什麼? | |
| 06 | 好的 CI/CD Pipeline 需要什麼? | 📍 你在這裡 |
| 07 | 好的監控系統需要什麼? | |
| 08 | 好的開發者體驗(DX)需要什麼? |