折腾侠
技术教程

CI/CD 流水线实战 - GitHub Actions 从入门到精通

CI/CD 怎么做?本文详解 GitHub Actions 和自动化部署实战。

折腾侠
2026/03/15 发布
9约 6 分钟489 字 / 1105 词00

CI/CD 流水线实战 - GitHub Actions 从入门到精通

CI/CD 怎么做?本文详解 GitHub Actions 和自动化部署实战。

📋 前言

CI/CD 是现代软件开发的标配。

CI/CD 是什么?

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

为什么需要 CI/CD?

  • 快速反馈
  • 减少人为错误
  • 提高交付速度
  • 保证代码质量

主流工具:

  • GitHub Actions(推荐)
  • Jenkins
  • GitLab CI
  • CircleCI

本文详解 GitHub Actions 实战。


🎯 GitHub Actions 基础

核心概念

概念说明
Workflow工作流,自动化流程
Event触发事件(push、PR 等)
Job工作流中的任务
Step任务中的步骤
Action可重用的操作单元

基本结构

YAML
name: CI/CD Pipeline

on:
  push:
    branches: [main]
  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'
      - name: Install dependencies
        run: npm install
      - name: Run tests
        run: npm test
      - name: Build
        run: npm run build

🚀 快速开始

1. 创建 Workflow 文件

Bash
# 项目根目录创建
mkdir -p .github/workflows
touch .github/workflows/ci.yml

2. 编写 CI 配置

YAML
# .github/workflows/ci.yml
name: Node.js CI

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

jobs:
  test:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [16, 18, 20]
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v3
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test
    
    - name: Build
      run: npm run build

3. 查看执行结果

GitHub 仓库 → Actions 标签页 → 查看运行记录

💡 实战场景

场景 1:Node.js 项目 CI/CD

YAML
name: Node.js Deploy

on:
  push:
    branches: [main]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test
    
    - name: Build
      run: npm run build
    
    - 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'

场景 2:Docker 镜像构建

YAML
name: Docker Build

on:
  push:
    tags: ['v*']

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v2
    
    - 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: |
          ${{ secrets.DOCKER_USERNAME }}/myapp:latest
          ${{ secrets.DOCKER_USERNAME }}/myapp:${{ github.ref_name }}

场景 3:多环境部署

YAML
name: Multi-Env Deploy

on:
  push:
    branches: [main, develop]

jobs:
  deploy-staging:
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    environment: staging
    
    steps:
    - uses: actions/checkout@v3
    - name: Deploy to Staging
      run: ./deploy.sh staging
      env:
        API_KEY: ${{ secrets.STAGING_API_KEY }}

  deploy-production:
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    
    steps:
    - uses: actions/checkout@v3
    - name: Deploy to Production
      run: ./deploy.sh production
      env:
        API_KEY: ${{ secrets.PRODUCTION_API_KEY }}

场景 4:定时任务

YAML
name: Daily Backup

on:
  schedule:
    # 每天凌晨 2 点执行(UTC 时间)
    - cron: '0 2 * * *'
  workflow_dispatch: # 允许手动触发

jobs:
  backup:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Run backup script
      run: ./scripts/backup.sh
      env:
        DB_HOST: ${{ secrets.DB_HOST }}
        DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
    
    - name: Upload backup to S3
      uses: aws-actions/configure-aws-credentials@v2
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        aws-region: us-east-1
    
    - name: Upload to S3
      run: aws s3 cp backup.sql s3://my-bucket/backups/

🔧 常用 Action

代码相关

YAML
# 检出代码
- uses: actions/checkout@v3

# 设置 Node.js
- uses: actions/setup-node@v3
  with:
    node-version: '18'
    cache: 'npm'

# 设置 Python
- uses: actions/setup-python@v4
  with:
    python-version: '3.11'

# 设置 Java
- uses: actions/setup-java@v3
  with:
    distribution: 'temurin'
    java-version: '17'

测试相关

YAML
# 运行测试
- name: Run tests
  run: npm test

# 代码覆盖率
- name: Upload coverage
  uses: codecov/codecov-action@v3
  with:
    file: ./coverage/lcov.info

# 运行 E2E 测试
- name: Run E2E tests
  uses: cypress-io/github-action@v5

部署相关

YAML
# 部署到 Vercel
- uses: amondnet/vercel-action@v20

# 部署到 Netlify
- uses: nwtgck/actions-netlify@v2

# 部署到 AWS
- uses: aws-actions/configure-aws-credentials@v2

# 部署到 Kubernetes
- uses: azure/k8s-deploy@v4

⚡ 高级特性

1. 缓存依赖

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-

2. 矩阵构建

YAML
strategy:
  matrix:
    os: [ubuntu-latest, windows-latest, macos-latest]
    node-version: [16, 18, 20]
    
steps:
- name: Test on ${{ matrix.os }} with Node.js ${{ matrix.node-version }}
  run: npm test

3. 条件执行

YAML
# 只在 main 分支执行
if: github.ref == 'refs/heads/main'

# 只在 tag 推送时执行
if: startsWith(github.ref, 'refs/tags/')

# 跳过某些情况
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}

4. 复用 Workflow

YAML
# .github/workflows/reusable.yml
name: Reusable Workflow

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
    - name: Deploy
      run: ./deploy.sh ${{ inputs.environment }}
YAML
# 调用复用 Workflow
name: Main Workflow

on: push

jobs:
  call-reusable:
    uses: ./.github/workflows/reusable.yml
    with:
      environment: production

5. 自定义 Action

YAML
# action.yml
name: 'My Custom Action'
description: 'Does something useful'
inputs:
  name:
    description: 'Name to greet'
    required: true
runs:
  using: 'node16'
  main: 'dist/index.js'
JavaScript
// index.js
const core = require('@actions/core');
const name = core.getInput('name');
core.setOutput('greeting', `Hello ${name}!`);

⚠️ 最佳实践

1. 安全管理

YAML
# ✅ 使用 Secrets
env:
  API_KEY: ${{ secrets.API_KEY }}

# ❌ 不要硬编码密码
env:
  API_KEY: my-secret-key  # 错误!

2. 固定 Action 版本

YAML
# ✅ 固定版本
- uses: actions/checkout@v3.0.0

# ❌ 使用 latest 标签
- uses: actions/checkout@latest

3. 超时设置

YAML
jobs:
  build:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    
    steps:
    - name: Long running task
      run: ./long-task.sh

4. 错误处理

YAML
steps:
- name: Try something
  run: ./script.sh
  continue-on-error: true
  
- name: Always run
  run: echo "This always runs"
  if: always()
  
- name: Run on failure
  run: echo "Something failed"
  if: failure()

5. 日志输出

YAML
- name: Debug info
  run: |
    echo "Node version: $(node -v)"
    echo "NPM version: $(npm -v)"
    echo "Working directory: $(pwd)"

🎯 完整示例

全栈应用 CI/CD

YAML
name: Full Stack CI/CD

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

env:
  NODE_VERSION: '18'
  PYTHON_VERSION: '3.11'

jobs:
  frontend-test:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./frontend
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
        cache-dependency-path: frontend/package-lock.json
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test
    
    - name: Build
      run: npm run build
    
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: frontend-build
        path: frontend/dist

  backend-test:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ./backend
    
    services:
      postgres:
        image: postgres:14
        env:
          POSTGRES_PASSWORD: postgres
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: ${{ env.PYTHON_VERSION }}
    
    - name: Install dependencies
      run: pip install -r requirements.txt
    
    - name: Run tests
      run: pytest
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test

  deploy:
    needs: [frontend-test, backend-test]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Download frontend build
      uses: actions/download-artifact@v3
      with:
        name: frontend-build
        path: ./frontend/dist
    
    - name: Deploy to production
      run: ./deploy.sh
      env:
        DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}

🎁 总结

核心概念:

✅ Workflow - 工作流配置
✅ Event - 触发条件
✅ Job - 工作任务
✅ Step - 执行步骤
✅ Action - 可复用操作
✅ Secret - 敏感信息

学习路径:

1. 理解基本概念
2. 编写简单 CI
3. 添加 CD 部署
4. 学习高级特性
5. 优化和定制

最后建议:

CI/CD 不是一蹴而就的。

从简单开始,逐步完善,持续优化。


你有什么 GitHub Actions 实战经验? 欢迎在评论区分享!👇

📚 参考资源

分享到:

如果这篇文章对你有帮助,欢迎请作者喝杯咖啡 ☕

加载评论中...