Skip to content

CI/CD 流程

一、CI/CD 概述

1.1 基本概念

  • CI (持续集成): 频繁将代码合并到主干,自动化测试
  • CD (持续交付/部署): 自动化部署到生产环境

1.2 典型流程

代码提交 → 代码检查 → 构建 → 测试 → 部署

二、GitHub Actions

2.1 基本结构

yaml
# .github/workflows/ci.yml
name: CI

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm run test

      - name: Build
        run: npm run build

2.2 常用触发器

yaml
on:
  # 推送触发
  push:
    branches: [main]
    paths:
      - 'src/**'
      - 'package.json'

  # PR 触发
  pull_request:
    types: [opened, synchronize]

  # 定时触发
  schedule:
    - cron: '0 2 * * *'  # 每天 2:00

  # 手动触发
  workflow_dispatch:
    inputs:
      environment:
        description: 'Environment to deploy'
        required: true
        default: 'staging'

  # 其他工作流完成后触发
  workflow_run:
    workflows: [Build]
    types: [completed]

2.3 环境变量与 Secrets

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      NODE_ENV: production

    steps:
      - name: Deploy
        env:
          AWS_ACCESS_KEY: ${{ secrets.AWS_ACCESS_KEY }}
          AWS_SECRET_KEY: ${{ secrets.AWS_SECRET_KEY }}
        run: |
          echo "Deploying to ${{ vars.DEPLOY_URL }}"

2.4 缓存依赖

yaml
- name: Cache node modules
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

# 或使用 setup-node 内置缓存
- uses: actions/setup-node@v3
  with:
    node-version: '18'
    cache: 'npm'

2.5 矩阵构建

yaml
jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node: [16, 18, 20]

    steps:
      - uses: actions/setup-node@v3
        with:
          node-version: ${{ matrix.node }}

2.6 多任务依赖

yaml
jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - run: npm test

  build:
    needs: [lint, test]  # 依赖前两个任务
    runs-on: ubuntu-latest
    steps:
      - run: npm run build

  deploy:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - run: npm run deploy

三、自动化测试

3.1 测试策略

yaml
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      # 单元测试
      - name: Unit Tests
        run: npm run test:unit

      # 集成测试
      - name: Integration Tests
        run: npm run test:integration

      # E2E 测试
      - name: E2E Tests
        uses: cypress-io/github-action@v5
        with:
          start: npm run dev
          wait-on: 'http://localhost:3000'

      # 上传覆盖率
      - name: Upload Coverage
        uses: codecov/codecov-action@v3

3.2 E2E 测试示例

yaml
jobs:
  e2e:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install dependencies
        run: npm ci

      - name: Install Playwright
        run: npx playwright install --with-deps

      - name: Run E2E tests
        run: npm run test:e2e

      - name: Upload test results
        if: always()
        uses: actions/upload-artifact@v3
        with:
          name: playwright-report
          path: playwright-report/

四、自动化部署

4.1 部署到 Vercel

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

4.2 部署到 AWS S3

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - run: npm ci && npm run build

      - name: Deploy to S3
        uses: jakejarvis/s3-sync-action@master
        with:
          args: --acl public-read --delete
        env:
          AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          SOURCE_DIR: 'dist'

      - name: Invalidate CloudFront
        uses: chetan/invalidate-cloudfront-action@v2
        env:
          DISTRIBUTION: ${{ secrets.DISTRIBUTION }}
          PATHS: '/*'

4.3 部署到服务器

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - run: npm ci && npm run build

      - name: Deploy to Server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          source: 'dist/*'
          target: '/var/www/html'

      - name: Restart Nginx
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_HOST }}
          username: ${{ secrets.SERVER_USER }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: sudo nginx -s reload

五、Docker 部署

5.1 Dockerfile

dockerfile
# 多阶段构建
FROM node:18-alpine AS builder

WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# 生产镜像
FROM nginx:alpine

COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf

EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

5.2 GitHub Actions 构建镜像

yaml
jobs:
  docker:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myorg/myapp:latest
            myorg/myapp:${{ github.sha }}

5.3 部署到 Kubernetes

yaml
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: azure/setup-kubectl@v3

      - uses: azure/k8s-set-context@v3
        with:
          kubeconfig: ${{ secrets.KUBE_CONFIG }}

      - run: |
          kubectl set image deployment/myapp \
            myapp=myorg/myapp:${{ github.sha }}

六、最佳实践

6.1 分支策略

main (生产) ← PR ← develop (开发) ← feature/*

                      release/*

6.2 环境管理

yaml
jobs:
  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    environment: staging

  deploy-production:
    if: github.ref == 'refs/heads/main'
    environment: production
    needs: deploy-staging

6.3 回滚机制

yaml
- name: Rollback on failure
  if: failure()
  run: |
    kubectl rollout undo deployment/myapp

七、高频面试题

Q1: CI/CD 的核心价值?

  1. 自动化减少人工错误
  2. 快速反馈代码问题
  3. 保持代码可随时发布
  4. 提高交付效率

Q2: GitHub Actions 的核心概念?

  • Workflow: 自动化流程
  • Job: 一组步骤
  • Step: 单个任务
  • Action: 可复用的任务单元

Q3: 如何优化 CI 速度?

  1. 依赖缓存
  2. 并行执行
  3. 增量构建
  4. 合理拆分 Job

前端面试知识库