name: ci-cd-pipeline description: 使用GitHub Actions、GitLab CI、Jenkins或类似工具设置和维护持续集成与持续部署管道,以自动化测试、构建和部署。适用于配置自动化构建、设置测试自动化、实施部署自动化、创建发布工作流、管理环境部署、配置构建缓存、实施蓝绿部署、设置回滚策略或自动化整个软件交付管道。
CI/CD管道 - 自动化构建、测试和部署
包管理器检测
重要:在创建CI/CD配置之前,通过检查锁定文件检测项目的包管理器,并相应调整所有命令。
检测顺序(首次匹配为准):
bun.lockb→ 使用 bunpnpm-lock.yaml→ 使用 pnpmyarn.lock→ 使用 yarnpackage-lock.json→ 使用 npm
命令映射 - 将本技能中的示例调整为检测到的包管理器:
| 操作 | npm | yarn | pnpm | bun |
|---|---|---|---|---|
| 安装(CI) | npm ci |
yarn install --frozen-lockfile |
pnpm install --frozen-lockfile |
bun install --frozen-lockfile |
| 运行脚本 | npm run <script> |
yarn <script> |
pnpm <script> |
bun run <script> |
| 执行二进制 | npx <cmd> |
yarn dlx <cmd> |
pnpm dlx <cmd> |
bunx <cmd> |
| 缓存键 | package-lock.json |
yarn.lock |
pnpm-lock.yaml |
bun.lockb |
| 缓存路径 | ~/.npm |
~/.yarn/cache |
~/.pnpm-store |
~/.bun/install/cache |
注意:以下示例默认使用npm。实施时,请替换为检测到的包管理器的相应命令。
何时使用此技能
- 设置GitHub Actions或GitLab CI工作流
- 自动化每次提交的测试执行
- 实施自动化构建和部署
- 创建发布和版本控制工作流
- 管理暂存和生产环境部署
- 配置构建缓存以加速管道
- 实施蓝绿或金丝雀部署
- 设置故障时自动回滚
- 在CI中运行代码检查和类型检查
- 自动化管道中的数据库迁移
- 在CI中实施安全扫描
- 创建部署审批工作流
何时使用此技能
- 设置持续集成、自动化部署、配置构建管道或实施DevOps工作流。
- 当处理相关任务或功能时
- 在需要此专业知识的开发过程中
使用时机:设置持续集成、自动化部署、配置构建管道或实施DevOps工作流。
核心原则
- 自动化一切 - 手动步骤易出错
- 快速失败 - 在管道早期发现问题
- 部署前测试 - 永不部署未经测试的代码
- 可重现构建 - 相同输入 = 相同输出
- 零停机部署 - 用户不受影响
GitHub Actions
1. 基础CI工作流
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 设置Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 安装依赖
run: npm ci
- name: 运行代码检查
run: npm run lint
- name: 运行类型检查
run: npm run typecheck
- name: 运行测试
run: npm test -- --coverage
- name: 上传覆盖率
uses: codecov/codecov-action@v3
with:
files: ./coverage/lcov.info
2. 矩阵测试
# 跨多个版本测试
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20, 21]
steps:
- uses: actions/checkout@v4
- name: 设置Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
3. 部署工作流
# .github/workflows/deploy.yml
name: 部署
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 设置Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
- name: 部署到Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'
4. Docker构建与推送
name: Docker
on:
push:
tags: ['v*']
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 设置Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 登录Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: 提取元数据
id: meta
uses: docker/metadata-action@v5
with:
images: myorg/myapp
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
- name: 构建并推送
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=registry,ref=myorg/myapp:buildcache
cache-to: type=registry,ref=myorg/myapp:buildcache,mode=max
5. 端到端测试
name: 端到端测试
on:
pull_request:
jobs:
e2e:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: 设置Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: 安装Playwright
run: npx playwright install --with-deps
- name: 运行端到端测试
run: npm run test:e2e
env:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test
- name: 上传测试结果
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
GitLab CI
# .gitlab-ci.yml
stages:
- lint
- test
- build
- deploy
variables:
NODE_VERSION: "20"
lint:
stage: lint
image: node:${NODE_VERSION}
script:
- npm ci
- npm run lint
- npm run typecheck
test:
stage: test
image: node:${NODE_VERSION}
services:
- postgres:15
variables:
POSTGRES_DB: test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
script:
- npm ci
- npm test -- --coverage
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
build:
stage: build
image: node:${NODE_VERSION}
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
deploy:production:
stage: deploy
image: node:${NODE_VERSION}
script:
- npm install -g vercel
- vercel --prod --token=$VERCEL_TOKEN
only:
- main
部署策略
1. 蓝绿部署
# 先部署到暂存槽
- name: 部署到暂存
run: |
az webapp deployment slot create \
--name myapp \
--resource-group mygroup \
--slot staging
az webapp deployment source config-zip \
--name myapp \
--resource-group mygroup \
--slot staging \
--src ./dist.zip
# 对暂存运行冒烟测试
- name: 冒烟测试
run: npm run test:smoke -- --url=https://myapp-staging.azurewebsites.net
# 将暂存切换到生产(即时切换)
- name: 切换到生产
run: |
az webapp deployment slot swap \
--name myapp \
--resource-group mygroup \
--slot staging \
--target-slot production
2. 金丝雀部署
# 先部署到10%的服务器
- name: 部署金丝雀
run: |
kubectl set image deployment/myapp \
myapp=myapp:${{ github.sha }} \
--record
kubectl patch deployment myapp \
-p '{"spec":{"replicas":1}}'
# 监控10分钟
- name: 监控金丝雀
run: |
sleep 600
ERROR_RATE=$(kubectl logs -l app=myapp --tail=1000 | grep ERROR | wc -l)
if [ $ERROR_RATE -gt 10 ]; then
echo "高错误率,回滚"
kubectl rollout undo deployment/myapp
exit 1
fi
# 如果健康,扩展到100%
- name: 完整部署
run: kubectl scale deployment myapp --replicas=5
3. 滚动部署
# Kubernetes滚动更新(零停机)
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 更新期间最多额外1个Pod
maxUnavailable: 1 # 最多1个Pod不可用
template:
spec:
containers:
- name: myapp
image: myapp:latest
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
管道最佳实践
1. 缓存
# 缓存依赖
- name: 缓存节点模块
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# 缓存构建输出
- name: 缓存构建
uses: actions/cache@v3
with:
path: .next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}
2. 密钥管理
# ✅ 将密钥存储在CI/CD平台中
jobs:
deploy:
steps:
- name: 部署
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: |
echo "API_KEY已设置: ${API_KEY:+yes}"
npm run deploy
# ✅ 使用Vault处理敏感数据
- name: 导入密钥
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/prod api_key | API_KEY ;
secret/data/prod db_url | DATABASE_URL
3. 质量门控
jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: 运行测试并计算覆盖率
run: npm test -- --coverage
- name: 检查覆盖率阈值
run: |
COVERAGE=$(cat coverage/coverage-summary.json | jq '.total.lines.pct')
if (( $(echo "$COVERAGE < 80" | bc -l) )); then
echo "覆盖率 $COVERAGE% 低于80%"
exit 1
fi
- name: SonarQube扫描
uses: sonarsource/sonarcloud-github-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- name: 检查质量门控
run: |
STATUS=$(curl -u $SONAR_TOKEN: \
"https://sonarcloud.io/api/qualitygates/project_status?projectKey=myproject" \
| jq -r '.projectStatus.status')
if [ "$STATUS" != "OK" ]; then
echo "质量门控失败"
exit 1
fi
4. 通知
jobs:
notify:
runs-on: ubuntu-latest
if: always()
needs: [test, build, deploy]
steps:
- name: Slack通知
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: '部署 ${{ job.status }}'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}
- name: 电子邮件通知
if: failure()
uses: dawidd6/action-send-mail@v3
with:
server_address: smtp.gmail.com
server_port: 465
username: ${{ secrets.MAIL_USERNAME }}
password: ${{ secrets.MAIL_PASSWORD }}
subject: 'CI/CD失败: ${{ github.workflow }}'
body: '构建在 ${{ github.ref }} 失败'
to: team@example.com
CI/CD检查清单
构建管道:
□ 每次提交自动运行
□ 运行代码检查和类型检查
□ 执行所有测试
□ 生成代码覆盖率报告
□ 构建生产工件
□ 缓存依赖以加速
质量门控:
□ 最低代码覆盖率阈值(例如80%)
□ 无关键漏洞(npm审计、Snyk)
□ 代码质量检查(SonarQube)
□ 无代码检查错误
□ 所有测试通过
部署:
□ 自动部署到暂存环境
□ 生产环境手动审批
□ 流量切换前健康检查
□ 回滚能力
□ 零停机策略(蓝绿、金丝雀、滚动)
安全:
□ 安全存储密钥(不在代码中)
□ 依赖扫描(Dependabot)
□ 容器漏洞扫描
□ SAST/DAST安全扫描
□ 要求签名提交
监控:
□ 构建状态通知(Slack、电子邮件)
□ 部署通知
□ 部署后错误率监控
□ 错误时自动回滚
□ 维护审计日志
资源
记住:优秀的CI/CD管道快速、可靠,并给予开发人员频繁部署的信心。