GitHub Actions CI/CD 自動化:從零建構完整部署流水線
11 分鐘閱讀 1,150 字
GitHub Actions CI/CD 自動化:從零建構完整部署流水線
GitHub Actions 讓 CI/CD 流水線的設定變得前所未有地簡單,直接在 GitHub 倉庫中定義工作流程,不需要額外的 CI 服務。本文從基礎概念到完整的部署流水線,帶你全面了解 GitHub Actions。
核心概念
- Workflow:由
.github/workflows/*.yml定義,由事件觸發 - Job:工作流程中的獨立執行單元,可並行或依序執行
- Step:Job 中的具體步驟,可執行命令或使用 Action
- Action:可複用的步驟單元,可從 Marketplace 引用或自訂
第一個 Workflow:PR 自動化測試
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
name: Test
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20, 22] # 多版本矩陣測試
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm test -- --coverage
- name: Upload coverage
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}快取策略
正確的快取設定能大幅縮短 CI 時間:
- name: Cache node_modules
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-使用 actions/setup-node@v4 的 cache 選項更簡潔(如上方範例)。
完整的 CI/CD 流水線
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
# Job 1:測試
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm test
# Job 2:建構 Docker 映像(依賴 test 通過)
build:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
image-tag: ${{ steps.meta.outputs.tags }}
steps:
- uses: actions/checkout@v4
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata for Docker
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=sha,prefix=sha-
type=ref,event=branch
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Job 3:部署到正式環境
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: production
url: https://myapp.example.com
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.DEPLOY_HOST }}
username: ${{ secrets.DEPLOY_USER }}
key: ${{ secrets.DEPLOY_SSH_KEY }}
script: |
cd /opt/myapp
docker pull ${{ needs.build.outputs.image-tag }}
docker compose up -d --no-deps app
docker image prune -f環境與機密管理
# 使用 GitHub Environments 進行分階段部署
deploy-staging:
environment: staging # 需要在 GitHub Settings 中設定
steps:
- run: echo "部署到測試環境"
deploy-production:
needs: deploy-staging
environment:
name: production
url: https://app.example.com
# 可設定必須手動審核才能繼續
steps:
- run: echo "部署到正式環境"可複用工作流程
# .github/workflows/reusable-deploy.yml
name: Reusable Deploy
on:
workflow_call: # 宣告為可被呼叫的工作流程
inputs:
environment:
required: true
type: string
secrets:
deploy-key:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy to ${{ inputs.environment }}
run: echo "Deploying to ${{ inputs.environment }}"# .github/workflows/main.yml
jobs:
deploy-prod:
uses: ./.github/workflows/reusable-deploy.yml
with:
environment: production
secrets:
deploy-key: ${{ secrets.PROD_DEPLOY_KEY }}自動化 PR 標籤
# .github/workflows/labeler.yml
name: PR Labeler
on:
pull_request:
types: [opened, synchronize]
jobs:
label:
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}定時任務
on:
schedule:
- cron: '0 2 * * *' # 每天凌晨 2 點(UTC)
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- name: Clean up old Docker images
run: |
# 清理超過 30 天的舊映像
echo "Running scheduled cleanup"費用優化技巧
- 使用快取:
actions/cache避免重複下載依賴 - 條件執行:
if: github.event_name == 'push'跳過不需要的 Job - 並行 Job:沒有依賴關係的 Job 設計成並行
- self-hosted runner:大量使用時考慮自建 Runner 節省費用
# 只在特定路徑變更時執行
on:
push:
paths:
- 'src/**'
- 'package.json'
- '!**.md' # 排除文件變更總結
GitHub Actions 的宣告式 YAML 設定、豐富的 Marketplace Actions 和與 GitHub 的深度整合,讓它成為中小型專案的首選 CI/CD 平台。關鍵是設計好 Job 的依賴關係、善用快取和 Environment 功能,以及將常用邏輯抽取為可複用工作流程。
分享這篇文章