GitHub Actions 入門設定
GitHub Actions 是 GitHub 原生的 CI/CD 服務,無需安裝任何伺服器。只需在專案根目錄建立 .github/workflows/ 資料夾,並新增 YAML 工作流程檔案即可啟用。每個 .yml 檔案代表一條獨立的 workflow,可依功能拆分,例如 ci.yml(測試)與 release.yml(發佈)分開管理,讓整體設定結構更清晰易讀。GitHub 會在每次符合觸發條件的事件發生時,自動掃描 .github/workflows/ 資料夾並執行對應的工作流程。
# .github/workflows/ci.yml — 完整的 GitHub Actions 工作流程範例
name: CI Pipeline
on:
push:
branches: [main, develop] # push 到 main 或 develop 時觸發
pull_request:
branches: [main] # 向 main 發起 PR 時觸發
schedule:
- cron: '0 2 * * 1' # 每週一凌晨 2 點自動執行(排程觸發)
jobs:
build-and-test:
runs-on: ubuntu-latest
strategy:
fail-fast: true # 矩陣中任一失敗立即取消其餘
matrix:
node-version: [18, 20, 22] # 矩陣測試多個 Node.js 版本
steps:
- name: 取出程式碼
uses: actions/checkout@v4
- name: 設定 Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm' # 自動快取 npm 相依套件
- name: 安裝相依套件
run: npm ci # ci 指令確保安裝結果與 lock 檔完全一致
- name: 執行 Lint 檢查
run: npm run lint
- name: 執行單元測試
run: npm test -- --coverage
- name: 建置專案
run: npm run build
- name: 上傳建置產物
uses: actions/upload-artifact@v4
with:
name: dist-node${{ matrix.node-version }}
path: dist/
retention-days: 7 # 7 天後自動清除,節省儲存空間工作流程目錄結構建議如下,依職責分檔管理,避免單一 YAML 過於龐大。明確的命名方式能讓整個團隊一眼看出每條 workflow 的觸發時機與用途:
.github/
└── workflows/
├── ci.yml # 測試與 Lint(所有分支 push 時觸發)
├── release.yml # 建置與發佈(語意化版本 tag 觸發)
├── deploy.yml # 部署至伺服器(main 分支 push 觸發)
└── scheduled.yml # 定期任務(cron 排程,例如安全掃描)GitLab CI 設定(.gitlab-ci.yml)
GitLab CI 設定集中於專案根目錄的 .gitlab-ci.yml。所有 stages 和 jobs 都定義在這一個檔案中,GitLab 在每次 push 時自動偵測並觸發 Pipeline。隨著專案規模增長,可使用 include 關鍵字將設定拆分至多個子檔案,例如將 Docker 相關 job 抽離為 .gitlab/ci/docker.yml,提升可維護性並讓團隊成員各自負責自己熟悉的部分。
# .gitlab-ci.yml — 包含四個 stage 的完整設定範例
stages:
- lint # 程式碼品質檢查(最快,優先執行,秒級完成)
- test # 單元測試與整合測試(含覆蓋率報告)
- build # 建置 Docker 映像或靜態資源
- deploy # 部署至目標環境(可設定手動核准)
variables:
NODE_ENV: production
DOCKER_DRIVER: overlay2
FF_USE_FASTZIP: "true" # GitLab Runner 效能旗標,加速 artifact 壓縮
default:
image: node:20-alpine # 所有 job 預設使用此 Docker 映像
before_script:
- npm ci --cache .npm --prefer-offline
cache:
key:
files:
- package-lock.json # 依 lock 檔案雜湊值建立 cache key
paths:
- .npm/ # 快取 npm 下載目錄,而非 node_modules
lint:
stage: lint
script:
- npm run lint
- npm run typecheck
allow_failure: false # lint 失敗則阻止後續所有 stage 執行
test:
stage: test
script:
- npm run test -- --coverage --ci
coverage: '/Lines\s*:\s*(\d+\.?\d*)%/' # 解析覆蓋率數字顯示於 MR
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
expire_in: 3 days
build:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/ # 傳遞給 deploy stage 使用
expire_in: 1 hour
deploy-staging:
stage: deploy
script:
- echo "部署到測試環境..."
environment:
name: staging
url: https://staging.example.com
rules:
- if: $CI_COMMIT_BRANCH == "main" # 只在 main 分支自動部署Runner 設定:GitHub-hosted vs Self-hosted
Runner 是實際執行 CI/CD 任務的工作節點,負責接收平台派發的 job 並在獨立環境中執行腳本。選擇哪種 Runner 類型取決於安全性需求、網路環境與成本考量:
# GitHub-hosted Runner — 零設定,直接指定系統映像
jobs:
build:
runs-on: ubuntu-latest # 也可用 windows-latest / macos-latest
# GitHub 自動分配虛擬機(2 核 7GB RAM),任務完成後立即回收
# Self-hosted Runner — 需自行安裝,但可存取內網資源與自訂環境
jobs:
deploy:
runs-on: [self-hosted, linux, deploy] # 以 labels 篩選指定 Runner安裝 Self-hosted Runner(GitHub Actions):前往 GitHub Repo → Settings → Actions → Runners → New self-hosted runner,依畫面提供的指令完成安裝。
# 以下為 Linux x64 安裝範例(版本號請以 GitHub 頁面顯示為準)
mkdir actions-runner && cd actions-runner
curl -o actions-runner-linux-x64-2.317.0.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz
tar xzf actions-runner-linux-x64-2.317.0.tar.gz
# 設定 Runner(貼上 GitHub 頁面提供的一次性 token)
./config.sh --url https://github.com/YOUR_ORG/YOUR_REPO \
--token YOUR_REGISTRATION_TOKEN \
--labels "deploy,production" # 自訂標籤,供 runs-on 篩選
# 以系統服務方式啟動(建議用於正式環境,確保重開機後自動重啟)
sudo ./svc.sh install
sudo ./svc.sh start安裝 GitLab Runner(Self-hosted):以 Docker 方式部署是生產環境的推薦做法,隔離性佳且升級方便。
# 以 Docker 方式運行 GitLab Runner(推薦用於生產)
docker run -d \
--name gitlab-runner \
--restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
# 前往 GitLab → Settings → CI/CD → Runners 取得 Registration Token
# 再執行 register 指令完成與 GitLab 的配對
sudo gitlab-runner register \
--non-interactive \
--url "https://gitlab.com/" \
--registration-token "YOUR_TOKEN" \
--executor "docker" \
--docker-image "docker:24.0" \
--description "production-runner" \
--tag-list "deploy,build,docker" \
--docker-privilegedtags(labels)後,可在 job 中使用 tags:(GitLab)或 runs-on:(GitHub)指定由特定 Runner 執行,確保部署任務只在具有正式環境存取權限的機器上執行,避免在共用 Runner 上暴露敏感憑證。環境變數與 Secrets 安全管理
CI/CD 管線中常需要存取 API 金鑰、資料庫密碼、SSH 私鑰等敏感資訊。這些資訊絕對不能直接寫在程式碼、YAML 設定檔或 Dockerfile 中,應使用平台提供的 Secrets 機制,讓 CI 平台在執行時以環境變數方式動態注入,確保敏感資料不會出現在任何版本控制紀錄中。
# GitHub Actions — 在 Repository Settings → Secrets and variables → Actions 新增
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # 使用 Environment Secrets(可設定審核保護機制)
steps:
- name: 部署至正式伺服器
env:
DEPLOY_KEY: ${{ secrets.DEPLOY_SSH_KEY }} # 敏感:SSH 私鑰
SERVER_HOST: ${{ secrets.PROD_SERVER_HOST }} # 敏感:伺服器 IP/域名
APP_ENV: ${{ vars.APP_ENV }} # 非敏感:一般設定值用 vars
run: |
echo "$DEPLOY_KEY" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no \
user@$SERVER_HOST "./deploy.sh"
rm -f /tmp/deploy_key # 使用後立即刪除金鑰檔,避免洩漏
# GitLab CI — 在 Settings → CI/CD → Variables 新增(可設定 Protected / Masked)
deploy:
stage: deploy
script:
- echo "$REGISTRY_PASSWORD" | docker login -u "$REGISTRY_USER" --password-stdin
- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
- docker push $CI_REGISTRY_IMAGE:latest本地測試 CI 設定(act 工具)
每次修改 CI 設定就需要推送程式碼才能驗證,既耗時又浪費 Pipeline 執行分鐘數,尤其在除錯 YAML 語法或 step 邏輯時格外痛苦。act 工具可在本機使用 Docker 容器模擬 GitHub Actions 執行環境,讓你在推送前即時驗證工作流程是否正確,大幅縮短 CI 開發的回饋循環。
# 安裝 act
brew install act # macOS(Homebrew)
choco install act-cli # Windows(Chocolatey)
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash # Linux
# 首次執行時 act 會詢問 Runner 映像大小(建議選 Medium,約 500MB)
act
# 常用指令
act --list # 列出所有可用的 workflow 與 job
act push # 模擬 push 事件,執行所有對應 workflow
act push --job build-and-test # 只執行指定名稱的 job
act pull_request # 模擬 PR 事件(測試 PR 觸發的 job)
act workflow_dispatch # 模擬手動觸發事件
# 指定較小的 Docker 映像(加快首次下載速度,適合 CI 環境)
act push -P ubuntu-latest=catthehacker/ubuntu:act-20.04
# 傳入本地 Secrets 檔案進行測試(格式與 .env 相同)
act push --secret-file .env.secrets
# Dry Run 模式(只驗證 YAML 語法與 job 結構,不實際執行)
act push --dryrun-P ubuntu-latest=catthehacker/ubuntu:act-20.04--secret-file .env.secrets這樣每次執行 act 時就會自動套用,不需要重複輸入參數。記得將 .env.secrets 加入 .gitignore,避免本地測試用的金鑰被意外提交。
常見設定錯誤與排除方法
以下是初學者最常遇到的 CI/CD 設定問題,以及對應的診斷方式與解決步驟。遇到問題時,優先查看 Pipeline log 的完整輸出,錯誤訊息通常已清楚指出問題所在:
- YAML 縮排錯誤(Tab vs 空格): YAML 規範只接受空格縮排,禁止使用 Tab 字元。許多編輯器預設以 Tab 縮排,從外部複製貼上程式碼時容易混入。建議在編輯器安裝 YAML 語法檢查外掛(如 VSCode 的 YAML 插件),或在終端機執行 yamllint .gitlab-ci.yml 驗證。GitLab 與 GitHub 的網頁介面也提供內建的 YAML 語法檢查器,可在提交前先行驗證。
-
Runner 權限不足(permission denied):
Runner 執行 Docker 指令時出現
Got permission denied while trying to connect to the Docker daemon socket,需確認 Runner 的執行用戶已加入docker群組:執行 sudo usermod -aG docker gitlab-runner 後重新啟動 Runner 服務。若確實需要在 Docker-in-Docker(DinD)環境中執行,則在 Runner 設定加入--docker-privileged旗標,但請注意 privileged 模式有安全風險,僅限受信任的自架環境使用。 -
Secrets 名稱大小寫不符:
環境變數名稱區分大小寫,
$deploy_key與$DEPLOY_KEY是完全不同的變數。CI 平台的 Secrets 通常以全大寫加底線格式命名(如DEPLOY_SSH_KEY),但在 script 中引用時必須完全一致,包括大小寫、底線與前綴。建議建立命名規範文件並在團隊中統一遵守,減少此類低級錯誤。 -
Artifact 路徑不存在導致後續 stage 失敗:
若 build job 因錯誤提前結束,artifact 路徑(如 dist/)可能從未被建立,但下一個 stage 的 job 仍嘗試存取該路徑而失敗。排查方式:先檢查 build job 的 log 找出真正的根本原因,而非僅修復下游 job。同時建議加上
when: always保存失敗時的 log 檔,或使用needs:搭配optional: true妥善處理選擇性依賴關係。