CI/CD管道设置与维护Skill ci-cd-pipeline

本技能专注于设置和维护持续集成与持续部署(CI/CD)管道,通过自动化构建、测试和部署流程,提升软件开发效率和质量。关键词包括持续集成、持续部署、自动化测试、DevOps、GitHub Actions、GitLab CI、Jenkins、构建缓存、蓝绿部署、金丝雀部署、滚动部署、回滚策略、软件交付管道,适用于DevOps工作流、云原生开发和自动化运维。

CI/CD 0 次安装 0 次浏览 更新于 3/18/2026

name: ci-cd-pipeline description: 使用GitHub Actions、GitLab CI、Jenkins或类似工具设置和维护持续集成与持续部署管道,以自动化测试、构建和部署。适用于配置自动化构建、设置测试自动化、实施部署自动化、创建发布工作流、管理环境部署、配置构建缓存、实施蓝绿部署、设置回滚策略或自动化整个软件交付管道。

CI/CD管道 - 自动化构建、测试和部署

包管理器检测

重要:在创建CI/CD配置之前,通过检查锁定文件检测项目的包管理器,并相应调整所有命令。

检测顺序(首次匹配为准):

  1. bun.lockb → 使用 bun
  2. pnpm-lock.yaml → 使用 pnpm
  3. yarn.lock → 使用 yarn
  4. package-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工作流。

核心原则

  1. 自动化一切 - 手动步骤易出错
  2. 快速失败 - 在管道早期发现问题
  3. 部署前测试 - 永不部署未经测试的代码
  4. 可重现构建 - 相同输入 = 相同输出
  5. 零停机部署 - 用户不受影响

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管道快速、可靠,并给予开发人员频繁部署的信心。