CI/CD 流水线搭建指南

两年前我们还是手动 FTP 上传代码,现在全自动 CI/CD。记录一下这个过程。

以前的痛

# 开发者电脑
npm run build
scp -r dist/* user@server:/var/www/html/

# 然后祈祷别出问题

问题:

  1. 每次部署 15 分钟
  2. 有人传错分支
  3. 没有回滚机制
  4. 出问题互相甩锅

现在的流程

代码提交 → 自动测试 → 自动构建 → 自动部署 → 通知

整个流程 5 分钟,人不用管。

GitHub Actions 配置

基础结构

# .github/workflows/deploy.yml
name: Deploy

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

jobs:
  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

  build:
    needs: 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 run build
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist

  deploy:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/download-artifact@v4
        with:
          name: dist
      - name: Deploy to server
        uses: appleboy/scp-action@v0.1.7
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.SSH_KEY }}
          source: "dist/*"
          target: "/var/www/html"

环境变量管理

敏感信息不要写进代码,用 GitHub Secrets:

Secret 名称用途
HOST服务器地址
USERNAMESSH 用户名
SSH_KEY私钥
DATABASE_URL数据库连接串

在 Settings → Secrets and variables → Actions 里配置。

GitHub Actions 日志

分环境部署

开发环境

每次 PR 自动部署到测试服务器:

deploy-dev:
  needs: build
  if: github.event_name == 'pull_request'
  runs-on: ubuntu-latest
  steps:
    - name: Deploy to dev
      run: |
        echo "Deploying PR #${{ github.event.number }} to dev server"
        # 部署逻辑

生产环境

只有 main 分支才部署:

deploy-prod:
  needs: build
  if: github.ref == 'refs/heads/main' && github.event_name == 'push'
  runs-on: ubuntu-latest
  steps:
    - name: Deploy to production
      run: |
        echo "Deploying to production"

部署确认

重要操作加人工确认:

deploy-prod:
  environment:
    name: production
    url: https://example.com

在 GitHub 上创建 Environment,配置 Required reviewers。部署前需要审批。

回滚机制

rollback:
  runs-on: ubuntu-latest
  steps:
    - name: Get previous release
      id: prev
      run: |
        PREV=$(ls -t /var/www/releases | head -2 | tail -1)
        echo "version=$PREV" >> $GITHUB_OUTPUT

    - name: Rollback
      run: |
        ln -sfn /var/www/releases/${{ steps.prev.outputs.version }} /var/www/html/current

保留最近 5 个版本,随时可以回滚。

通知

部署结果发到钉钉/飞书:

notify:
  runs-on: ubuntu-latest
  needs: [deploy]
  if: always()
  steps:
    - name: Notify
      uses: actionsflow/action-dingtalk@v1
      with:
        webhook: ${{ secrets.DINGTALK_WEBHOOK }}
        content: |
          项目: ${{ github.repository }}
          分支: ${{ github.ref }}
          状态: ${{ job.status }}
          提交者: ${{ github.actor }}

性能优化

优化项效果
npm cache节省 30s
并行任务节省 2min
增量构建节省 1min
取消旧构建节省资源

配置缓存:

- uses: actions/setup-node@v4
  with:
    node-version: 20
    cache: npm  # 启用缓存

CI/CD 流程图

常见问题

1. 构建超时

默认超时 6 小时,可以调整:

jobs:
  build:
    timeout-minutes: 30

2. 磁盘空间不足

Runner 只有 14GB,大项目可能不够:

- name: Free disk space
  run: |
    sudo rm -rf /usr/share/dotnet
    sudo rm -rf /opt/ghc

3. 权限问题

- name: Fix permissions
  run: sudo chown -R $USER:$USER .

成本

GitHub Actions 免费额度:

  • 公开仓库:无限
  • 私有仓库:2000 分钟/月

我们团队每月用约 1500 分钟,免费额度够用。

总结

CI/CD 带来的好处:

  1. 部署时间从 15 分钟到 5 分钟
  2. 人力投入减少 80%
  3. 人为错误几乎为零
  4. 出问题可以快速回滚

投入产出比很高,每个团队都应该做。

不要追求完美,先跑起来再优化。我们从最简单的手动触发部署开始,逐步加自动化,花了一个月才搞完。