GitHub Actions CI/CD 自动化部署完全指南

GitHub Actions CI/CD 自动化部署完全指南

文章目录

  • [GitHub Actions CI/CD 自动化部署完全指南](#GitHub Actions CI/CD 自动化部署完全指南)
    • [什么是 CI/CD 和 GitHub Actions](#什么是 CI/CD 和 GitHub Actions)
      • [CI/CD 概念](#CI/CD 概念)
      • [GitHub Actions 简介](#GitHub Actions 简介)
        • [🚀 主要优势](#🚀 主要优势)
        • [📊 使用统计](#📊 使用统计)
    • [GitHub Actions 核心概念](#GitHub Actions 核心概念)
      • 基本组件
        • [1. **Workflow(工作流)**](#1. Workflow(工作流))
        • [2. **Event(事件)**](#2. Event(事件))
        • [3. **Job(作业)**](#3. Job(作业))
        • [4. **Step(步骤)**](#4. Step(步骤))
        • [5. **Action(动作)**](#5. Action(动作))
        • [6. **Runner(运行器)**](#6. Runner(运行器))
      • 工作流语法结构
    • 基础工作流配置
      • 创建第一个工作流
        • [1. 创建工作流文件](#1. 创建工作流文件)
        • [2. 常用触发事件](#2. 常用触发事件)
        • [3. 环境变量配置](#3. 环境变量配置)
    • [前端项目 CI/CD 实践](#前端项目 CI/CD 实践)
      • [React 项目完整工作流](#React 项目完整工作流)
      • [Vue.js 项目工作流](#Vue.js 项目工作流)
    • [后端项目 CI/CD 实践](#后端项目 CI/CD 实践)
      • [Node.js Express 应用](#Node.js Express 应用)
      • [Python Django 应用](#Python Django 应用)
    • [全栈项目 CI/CD 实践](#全栈项目 CI/CD 实践)
      • [Monorepo 项目结构](#Monorepo 项目结构)
    • 安全性和性能优化
      • 安全最佳实践
        • [1. **Secrets 管理**](#1. Secrets 管理)
        • [2. **权限最小化**](#2. 权限最小化)
        • [3. **依赖安全扫描**](#3. 依赖安全扫描)
        • [4. **环境隔离和保护**](#4. 环境隔离和保护)
      • 性能优化策略
        • [1. **缓存优化**](#1. 缓存优化)
        • [2. **并行执行优化**](#2. 并行执行优化)
        • [3. **资源优化**](#3. 资源优化)
    • 常见问题和解决方案
      • 构建和部署问题
        • [1. **依赖安装失败**](#1. 依赖安装失败)
        • [2. **Docker 构建失败**](#2. Docker 构建失败)
        • [3. **测试超时或失败**](#3. 测试超时或失败)
      • 权限和安全问题
        • [1. **权限被拒绝错误**](#1. 权限被拒绝错误)
        • [2. **Secrets 访问问题**](#2. Secrets 访问问题)
      • 性能问题
        • [1. **构建时间过长**](#1. 构建时间过长)
        • [2. **资源限制问题**](#2. 资源限制问题)
      • 调试技巧
        • [1. **启用调试日志**](#1. 启用调试日志)
        • [2. **条件调试**](#2. 条件调试)
    • 总结
  • 部署
    • 总结
      • [🎯 核心收获](#🎯 核心收获)
      • [📈 进阶建议](#📈 进阶建议)
      • [🔗 有用资源](#🔗 有用资源)
      • [🚀 下一步行动](#🚀 下一步行动)
  • 部署

什么是 CI/CD 和 GitHub Actions

CI/CD 概念

持续集成(Continuous Integration, CI) 是一种开发实践,开发者频繁地将代码集成到主分支中,每次集成都通过自动化构建来验证,从而尽早发现集成错误。

持续部署(Continuous Deployment, CD) 是在持续集成的基础上,将通过测试的代码自动部署到生产环境的实践。

GitHub Actions 简介

GitHub Actions 是 GitHub 提供的 CI/CD 平台,允许您直接在 GitHub 仓库中自动化软件开发工作流程。

🚀 主要优势
  • 原生集成:与 GitHub 仓库无缝集成
  • 免费额度:公共仓库免费,私有仓库每月 2000 分钟免费
  • 丰富的 Actions 市场:数千个预构建的 Actions 可供使用
  • 多平台支持:支持 Linux、Windows、macOS
  • 灵活配置:支持复杂的工作流程和条件执行
📊 使用统计
复制代码
GitHub Actions 使用数据:
- 超过 300 万个组织在使用
- 每月执行超过 10 亿次工作流
- 市场中有超过 20,000 个 Actions

GitHub Actions 核心概念

基本组件

1. Workflow(工作流)
  • 定义在 .github/workflows/ 目录下的 YAML 文件
  • 包含一个或多个 Jobs
  • 由特定事件触发
2. Event(事件)
  • 触发工作流的特定活动
  • 常见事件:pushpull_requestscheduleworkflow_dispatch
3. Job(作业)
  • 工作流中的一组步骤
  • 在同一个运行器上执行
  • 可以并行或串行执行
4. Step(步骤)
  • Job 中的单个任务
  • 可以运行命令或使用 Action
5. Action(动作)
  • 可重用的代码单元
  • 可以是自定义的或来自市场
6. Runner(运行器)
  • 执行工作流的服务器
  • GitHub 提供托管运行器,也可以自托管

工作流语法结构

yaml 复制代码
name: 工作流名称

# 触发条件
on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main ]

# 环境变量
env:
  NODE_VERSION: '18'

# 作业定义
jobs:
  job-name:
    runs-on: ubuntu-latest
    
    steps:
    - name: 步骤名称
      uses: actions/checkout@v4
      
    - name: 另一个步骤
      run: echo "Hello World"

基础工作流配置

创建第一个工作流

1. 创建工作流文件

在项目根目录创建 .github/workflows/ci.yml

yaml 复制代码
name: Basic CI

# 触发条件:推送到 main 分支或创建 PR
on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  test:
    name: 运行测试
    runs-on: ubuntu-latest
    
    steps:
    # 检出代码
    - name: Checkout code
      uses: actions/checkout@v4
    
    # 设置 Node.js 环境
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
    
    # 安装依赖
    - name: Install dependencies
      run: npm ci
    
    # 运行测试
    - name: Run tests
      run: npm test
    
    # 运行代码检查
    - name: Run linting
      run: npm run lint
2. 常用触发事件
yaml 复制代码
on:
  # 推送到指定分支
  push:
    branches: [ main, develop ]
    paths:
      - 'src/**'
      - 'package.json'
  
  # Pull Request
  pull_request:
    branches: [ main ]
    types: [opened, synchronize, reopened]
  
  # 定时执行
  schedule:
    - cron: '0 2 * * *'  # 每天凌晨2点
  
  # 手动触发
  workflow_dispatch:
    inputs:
      environment:
        description: '部署环境'
        required: true
        default: 'staging'
        type: choice
        options:
        - staging
        - production
  
  # 发布 Release
  release:
    types: [published]
3. 环境变量配置
yaml 复制代码
env:
  # 全局环境变量
  NODE_VERSION: '18'
  REGISTRY_URL: 'https://registry.npmjs.org'

jobs:
  build:
    runs-on: ubuntu-latest
    
    env:
      # Job 级别环境变量
      BUILD_ENV: production
    
    steps:
    - name: Build application
      env:
        # Step 级别环境变量
        API_URL: ${{ secrets.API_URL }}
      run: |
        echo "Node version: $NODE_VERSION"
        echo "Build environment: $BUILD_ENV"
        echo "API URL: $API_URL"

前端项目 CI/CD 实践

React 项目完整工作流

yaml 复制代码
name: React App CI/CD

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

env:
  NODE_VERSION: '18'
  REGISTRY_URL: 'https://registry.npmjs.org'

jobs:
  # 代码质量检查
  quality-check:
    name: 代码质量检查
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
        registry-url: ${{ env.REGISTRY_URL }}
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run ESLint
      run: npm run lint
    
    - name: Run Prettier check
      run: npm run format:check
    
    - name: Run type check
      run: npm run type-check
    
    - name: Run tests with coverage
      run: npm run test:coverage
    
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info
        flags: unittests
        name: codecov-umbrella

  # 构建应用
  build:
    name: 构建应用
    runs-on: ubuntu-latest
    needs: quality-check
    
    strategy:
      matrix:
        environment: [staging, production]
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Build for ${{ matrix.environment }}
      env:
        REACT_APP_ENV: ${{ matrix.environment }}
        REACT_APP_API_URL: ${{ secrets[format('API_URL_{0}', matrix.environment)] }}
      run: npm run build
    
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-${{ matrix.environment }}
        path: build/
        retention-days: 7

  # 部署到 Vercel
  deploy-vercel:
    name: 部署到 Vercel
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Download build artifacts
      uses: actions/download-artifact@v3
      with:
        name: build-production
        path: build/
    
    - name: Deploy to 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 }}
        working-directory: ./
        vercel-args: '--prod'

  # 部署到 Netlify
  deploy-netlify:
    name: 部署到 Netlify
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    
    steps:
    - name: Download build artifacts
      uses: actions/download-artifact@v3
      with:
        name: build-staging
        path: build/
    
    - name: Deploy to Netlify
      uses: nwtgck/actions-netlify@v2.0
      with:
        publish-dir: './build'
        production-branch: main
        github-token: ${{ secrets.GITHUB_TOKEN }}
        deploy-message: "Deploy from GitHub Actions"
      env:
        NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
        NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

Vue.js 项目工作流

yaml 复制代码
name: Vue.js App CI/CD

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

jobs:
  test-and-build:
    name: 测试和构建
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [16, 18, 20]
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run unit tests
      run: npm run test:unit
    
    - name: Run e2e tests
      run: npm run test:e2e:headless
    
    - name: Build application
      run: npm run build
    
    - name: Upload build artifacts
      if: matrix.node-version == 18
      uses: actions/upload-artifact@v3
      with:
        name: vue-build
        path: dist/

  deploy:
    name: 部署应用
    runs-on: ubuntu-latest
    needs: test-and-build
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Download build artifacts
      uses: actions/download-artifact@v3
      with:
        name: vue-build
        path: dist/
    
    - name: Deploy to GitHub Pages
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./dist

后端项目 CI/CD 实践

Node.js Express 应用

yaml 复制代码
name: Node.js Express API CI/CD

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

env:
  NODE_VERSION: '18'
  DOCKER_REGISTRY: 'ghcr.io'

jobs:
  # 测试阶段
  test:
    name: 运行测试
    runs-on: ubuntu-latest
    
    services:
      # PostgreSQL 服务
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: test_db
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
      
      # Redis 服务
      redis:
        image: redis:7
        options: >-
          --health-cmd "redis-cli ping"
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 6379:6379
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run database migrations
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
      run: npm run db:migrate
    
    - name: Run unit tests
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
        REDIS_URL: redis://localhost:6379
      run: npm run test
    
    - name: Run integration tests
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
        REDIS_URL: redis://localhost:6379
      run: npm run test:integration
    
    - name: Generate test coverage
      run: npm run test:coverage
    
    - name: Upload coverage reports
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info

  # 安全扫描
  security-scan:
    name: 安全扫描
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Run npm audit
      run: npm audit --audit-level moderate
    
    - name: Run Snyk security scan
      uses: snyk/actions/node@master
      env:
        SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      with:
        args: --severity-threshold=high

  # 构建 Docker 镜像
  build-docker:
    name: 构建 Docker 镜像
    runs-on: ubuntu-latest
    needs: [test, security-scan]
    
    steps:
    - name: Checkout code
      uses: actions/checkout@v4
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Login to Container Registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.DOCKER_REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=sha,prefix={{branch}}-
          type=raw,value=latest,enable={{is_default_branch}}
    
    - name: Build and push Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        platforms: linux/amd64,linux/arm64
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

  # 部署到 staging
  deploy-staging:
    name: 部署到 Staging
    runs-on: ubuntu-latest
    needs: build-docker
    if: github.ref == 'refs/heads/develop'
    environment: staging
    
    steps:
    - name: Deploy to staging server
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.STAGING_HOST }}
        username: ${{ secrets.STAGING_USER }}
        key: ${{ secrets.STAGING_SSH_KEY }}
        script: |
          docker pull ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}:develop
          docker stop api-staging || true
          docker rm api-staging || true
          docker run -d \
            --name api-staging \
            --restart unless-stopped \
            -p 3000:3000 \
            -e NODE_ENV=staging \
            -e DATABASE_URL=${{ secrets.STAGING_DATABASE_URL }} \
            ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}:develop

  # 部署到 production
  deploy-production:
    name: 部署到 Production
    runs-on: ubuntu-latest
    needs: build-docker
    if: github.ref == 'refs/heads/main'
    environment: production
    
    steps:
    - name: Deploy to Kubernetes
      uses: azure/k8s-deploy@v1
      with:
        manifests: |
          k8s/deployment.yaml
          k8s/service.yaml
        images: |
          ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}:latest
        kubeconfig: ${{ secrets.KUBE_CONFIG }}

Python Django 应用

yaml 复制代码
name: Django App CI/CD

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

jobs:
  test:
    name: 测试 Django 应用
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        python-version: [3.9, 3.10, 3.11]
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: django_test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up Python ${{ matrix.python-version }}
      uses: actions/setup-python@v4
      with:
        python-version: ${{ matrix.python-version }}
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        pip install -r requirements-dev.txt
    
    - name: Run migrations
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_test
      run: python manage.py migrate
    
    - name: Run tests
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_test
      run: |
        python manage.py test
        coverage run --source='.' manage.py test
        coverage xml
    
    - name: Upload coverage to Codecov
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage.xml

  deploy:
    name: 部署到 Heroku
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Deploy to Heroku
      uses: akhileshns/heroku-deploy@v3.12.14
      with:
        heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
        heroku_app_name: "your-django-app"
        heroku_email: "your-email@example.com"

全栈项目 CI/CD 实践

Monorepo 项目结构

yaml 复制代码
name: Full Stack Monorepo CI/CD

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

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

jobs:
  # 检测变更
  detect-changes:
    name: 检测文件变更
    runs-on: ubuntu-latest
    outputs:
      frontend: ${{ steps.changes.outputs.frontend }}
      backend: ${{ steps.changes.outputs.backend }}
      shared: ${{ steps.changes.outputs.shared }}
    
    steps:
    - uses: actions/checkout@v4
    
    - uses: dorny/paths-filter@v2
      id: changes
      with:
        filters: |
          frontend:
            - 'frontend/**'
            - 'shared/**'
          backend:
            - 'backend/**'
            - 'shared/**'
          shared:
            - 'shared/**'

  # 前端测试和构建
  frontend-ci:
    name: 前端 CI
    runs-on: ubuntu-latest
    needs: detect-changes
    if: needs.detect-changes.outputs.frontend == 'true'
    
    defaults:
      run:
        working-directory: ./frontend
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      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 application
      run: npm run build
    
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: frontend-build
        path: frontend/dist/

  # 后端测试
  backend-ci:
    name: 后端 CI
    runs-on: ubuntu-latest
    needs: detect-changes
    if: needs.detect-changes.outputs.backend == 'true'
    
    defaults:
      run:
        working-directory: ./backend
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: test_db
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: ${{ env.PYTHON_VERSION }}
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run tests
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
      run: pytest

  # 集成测试
  integration-test:
    name: 集成测试
    runs-on: ubuntu-latest
    needs: [frontend-ci, backend-ci]
    if: always() && (needs.frontend-ci.result == 'success' || needs.frontend-ci.result == 'skipped') && (needs.backend-ci.result == 'success' || needs.backend-ci.result == 'skipped')
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
    
    - name: Install Playwright
      run: |
        npm install -g @playwright/test
        npx playwright install
    
    - name: Start services with Docker Compose
      run: docker-compose -f docker-compose.test.yml up -d
    
    - name: Wait for services
      run: |
        timeout 60 bash -c 'until curl -f http://localhost:3000/health; do sleep 2; done'
        timeout 60 bash -c 'until curl -f http://localhost:8000/health; do sleep 2; done'
    
    - name: Run E2E tests
      run: npx playwright test
    
    - name: Upload test results
      uses: actions/upload-artifact@v3
      if: always()
      with:
        name: playwright-report
        path: playwright-report/

  # 部署
  deploy:
    name: 部署
    runs-on: ubuntu-latest
    needs: [frontend, backend, e2e]
    if: github.ref == 'refs/heads/main' && success()
    
    steps:
    - name: Download frontend build
      uses: actions/download-artifact@v3
      with:
        name: frontend-build
        path: frontend-dist/
    
    - name: Deploy frontend to CDN
      run: |
        # 部署前端到 CDN
        echo "Deploying frontend to CDN..."
    
    - name: Deploy backend to Kubernetes
      run: |
        # 部署后端到 K8s
        echo "Deploying backend to Kubernetes..."

安全性和性能优化

安全最佳实践

1. Secrets 管理
yaml 复制代码
name: Secure CI/CD

on:
  push:
    branches: [ main ]

jobs:
  secure-build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    # ✅ 正确的 secrets 使用
    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v4
      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: Debug secrets
    #   run: echo "API Key: ${{ secrets.API_KEY }}"
    
    # ✅ 正确:使用环境变量
    - name: Deploy with secrets
      env:
        API_KEY: ${{ secrets.API_KEY }}
        DATABASE_URL: ${{ secrets.DATABASE_URL }}
      run: |
        # 使用环境变量而不是直接引用 secrets
        ./deploy.sh
2. 权限最小化
yaml 复制代码
name: Minimal Permissions

on:
  push:
    branches: [ main ]

# 设置最小权限
permissions:
  contents: read
  packages: write
  security-events: write

jobs:
  build:
    runs-on: ubuntu-latest
    
    # Job 级别权限覆盖
    permissions:
      contents: read
      packages: write
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Build and push Docker image
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ghcr.io/${{ github.repository }}:latest
3. 依赖安全扫描
yaml 复制代码
name: Security Scanning

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 6 * * 1'  # 每周一早上6点

jobs:
  security-scan:
    name: 安全扫描
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    # npm 审计
    - name: Run npm audit
      run: |
        npm audit --audit-level moderate
        npm audit fix --dry-run
    
    # Snyk 安全扫描
    - name: Run Snyk to check for vulnerabilities
      uses: snyk/actions/node@master
      env:
        SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      with:
        args: --severity-threshold=high --fail-on=upgradable
    
    # CodeQL 代码分析
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v2
      with:
        languages: javascript, typescript
    
    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v2
    
    # 容器镜像扫描
    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: 'myapp:latest'
        format: 'sarif'
        output: 'trivy-results.sarif'
    
    - name: Upload Trivy scan results
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: 'trivy-results.sarif'
4. 环境隔离和保护
yaml 复制代码
name: Environment Protection

on:
  push:
    branches: [ main, develop ]

jobs:
  deploy-staging:
    name: 部署到 Staging
    runs-on: ubuntu-latest
    environment: staging
    if: github.ref == 'refs/heads/develop'
    
    steps:
    - name: Deploy to staging
      run: echo "Deploying to staging environment"

  deploy-production:
    name: 部署到 Production
    runs-on: ubuntu-latest
    environment: 
      name: production
      url: https://myapp.com
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Deploy to production
      run: echo "Deploying to production environment"

性能优化策略

1. 缓存优化
yaml 复制代码
name: Optimized Caching

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    # Node.js 依赖缓存
    - name: Setup Node.js with cache
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
        cache-dependency-path: |
          package-lock.json
          frontend/package-lock.json
          backend/package-lock.json
    
    # 自定义缓存
    - name: Cache node modules
      uses: actions/cache@v3
      with:
        path: |
          ~/.npm
          node_modules
          */node_modules
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-
    
    # Docker 层缓存
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Build with cache
      uses: docker/build-push-action@v5
      with:
        context: .
        cache-from: type=gha
        cache-to: type=gha,mode=max
        push: true
        tags: myapp:latest
2. 并行执行优化
yaml 复制代码
name: Parallel Execution

on:
  push:
    branches: [ main ]

jobs:
  # 并行测试矩阵
  test:
    name: 测试
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        node-version: [16, 18, 20]
        test-suite: [unit, integration, e2e]
      fail-fast: false  # 不因单个失败而停止所有任务
      max-parallel: 6   # 最大并行数
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run ${{ matrix.test-suite }} tests
      run: npm run test:${{ matrix.test-suite }}

  # 并行构建不同平台
  build:
    name: 构建
    runs-on: ubuntu-latest
    needs: test
    
    strategy:
      matrix:
        platform: [linux/amd64, linux/arm64]
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Set up QEMU
      uses: docker/setup-qemu-action@v3
    
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Build for ${{ matrix.platform }}
      uses: docker/build-push-action@v5
      with:
        context: .
        platforms: ${{ matrix.platform }}
        push: true
        tags: myapp:${{ matrix.platform }}
3. 资源优化
yaml 复制代码
name: Resource Optimization

on:
  push:
    branches: [ main ]

jobs:
  optimized-build:
    name: 优化构建
    runs-on: ubuntu-latest
    
    # 设置超时时间
    timeout-minutes: 30
    
    steps:
    - uses: actions/checkout@v4
      with:
        # 浅克隆以减少下载时间
        fetch-depth: 1
    
    # 只在需要时安装依赖
    - name: Check if dependencies changed
      uses: dorny/paths-filter@v2
      id: changes
      with:
        filters: |
          deps:
            - 'package*.json'
            - 'yarn.lock'
    
    - name: Setup Node.js
      if: steps.changes.outputs.deps == 'true'
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
    
    - name: Install dependencies
      if: steps.changes.outputs.deps == 'true'
      run: npm ci --prefer-offline --no-audit
    
    # 条件执行构建
    - name: Build application
      if: steps.changes.outputs.deps == 'true' || github.event_name == 'push'
      run: npm run build

常见问题和解决方案

构建和部署问题

1. 依赖安装失败

问题描述npm cinpm install 失败

常见原因和解决方案

yaml 复制代码
# 解决方案 1:清理缓存
- name: Clear npm cache
  run: npm cache clean --force

- name: Install dependencies
  run: npm ci

# 解决方案 2:使用不同的 registry
- name: Setup Node.js
  uses: actions/setup-node@v4
  with:
    node-version: '18'
    registry-url: 'https://registry.npmmirror.com'

# 解决方案 3:忽略可选依赖
- name: Install dependencies
  run: npm ci --no-optional

# 解决方案 4:增加超时时间
- name: Install dependencies
  run: npm ci --timeout=300000
2. Docker 构建失败

问题描述:Docker 镜像构建过程中出错

yaml 复制代码
# 解决方案 1:多阶段构建优化
# Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force

FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

# 解决方案 2:增加构建资源
- name: Build Docker image
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: myapp:latest
    build-args: |
      BUILDKIT_INLINE_CACHE=1
    cache-from: type=gha
    cache-to: type=gha,mode=max
3. 测试超时或失败
yaml 复制代码
# 解决方案 1:增加测试超时时间
- name: Run tests
  run: npm test
  timeout-minutes: 10

# 解决方案 2:并行测试
- name: Run tests in parallel
  run: npm test -- --maxWorkers=2

# 解决方案 3:重试机制
- name: Run tests with retry
  uses: nick-invision/retry@v2
  with:
    timeout_minutes: 5
    max_attempts: 3
    command: npm test

权限和安全问题

1. 权限被拒绝错误
yaml 复制代码
# 问题:Permission denied
# 解决方案:设置正确的权限
permissions:
  contents: read
  packages: write
  deployments: write

# 或者在 job 级别设置
jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    steps:
    # ...
2. Secrets 访问问题
yaml 复制代码
# 问题:无法访问 secrets
# 解决方案 1:检查 secrets 名称
- name: Use secret
  env:
    API_KEY: ${{ secrets.API_KEY }}  # 确保名称正确
  run: echo "Using API key"

# 解决方案 2:环境级别的 secrets
jobs:
  deploy:
    environment: production  # 使用环境级别的 secrets
    steps:
    - name: Deploy
      env:
        DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
      run: ./deploy.sh

性能问题

1. 构建时间过长
yaml 复制代码
# 解决方案 1:使用缓存
- name: Cache dependencies
  uses: actions/cache@v3
  with:
    path: ~/.npm
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

# 解决方案 2:并行构建
strategy:
  matrix:
    component: [frontend, backend, api]
  max-parallel: 3

# 解决方案 3:条件执行
- name: Build only if changed
  if: steps.changes.outputs.src == 'true'
  run: npm run build
2. 资源限制问题
yaml 复制代码
# 解决方案 1:使用更大的运行器
jobs:
  build:
    runs-on: ubuntu-latest-4-cores  # 使用更多 CPU 核心

# 解决方案 2:优化内存使用
- name: Build with memory optimization
  run: |
    export NODE_OPTIONS="--max-old-space-size=4096"
    npm run build

调试技巧

1. 启用调试日志
yaml 复制代码
# 启用 Actions 调试
- name: Debug information
  run: |
    echo "Runner OS: ${{ runner.os }}"
    echo "GitHub ref: ${{ github.ref }}"
    echo "Event name: ${{ github.event_name }}"
    env

# 启用 npm 调试
- name: Install with debug
  run: npm ci --loglevel verbose

# 启用 Docker 调试
- name: Build Docker with debug
  run: |
    export DOCKER_BUILDKIT=1
    export BUILDKIT_PROGRESS=plain
    docker build --progress=plain .
2. 条件调试
yaml 复制代码
- name: Debug on failure
  if: failure()
  run: |
    echo "Build failed, collecting debug info..."
    ls -la
    cat package.json
    npm ls --depth=0

总结

关键要点

  1. 渐进式采用:从简单的 CI 开始,逐步添加 CD 功能
  2. 安全第一:始终遵循安全最佳实践,保护敏感信息
  3. 性能优化:合理使用缓存和并行执行提高效率
  4. 监控和反馈:建立完善的监控和通知机制
  5. 文档化:维护清晰的工作流文档和最佳实践

最佳实践总结

✅ 推荐做法
  • 使用语义化的工作流和作业名称
  • 合理设置触发条件,避免不必要的执行
  • 充分利用缓存机制提高构建速度
  • 实施全面的测试策略(单元测试、集成测试、E2E 测试)
  • 使用环境保护和审批流程
  • 定期更新 Actions 版本
  • 监控工作流执行时间和成本
❌ 避免的做法
  • 在日志中暴露敏感信息
  • 使用过于宽泛的权限
  • 忽略安全扫描和依赖更新
  • 创建过于复杂的单一工作流
  • 缺乏错误处理和重试机制
  • 不使用环境变量管理配置

进阶学习路径

  1. 基础阶段

    • 掌握 YAML 语法和 GitHub Actions 基本概念
    • 创建简单的 CI 工作流
    • 学习常用的官方 Actions
  2. 中级阶段

    • 实现完整的 CI/CD 流水线
    • 掌握矩阵构建和并行执行
    • 学习 Docker 集成和容器化部署
  3. 高级阶段

    • 创建自定义 Actions
    • 实现复杂的部署策略(蓝绿部署、金丝雀发布)
    • 集成监控和可观测性工具

参考资料

官方文档
社区资源
工具和服务
博客和教程

结语

GitHub Actions 为现代软件开发提供了强大而灵活的 CI/CD 解决方案。通过本指南的学习和实践,您应该能够:

  • 理解 CI/CD 的核心概念和价值
  • 掌握 GitHub Actions 的基本使用方法
  • 为不同类型的项目设计合适的工作流
  • 实施安全和性能最佳实践
  • 解决常见的构建和部署问题

记住,CI/CD 是一个持续改进的过程。随着项目的发展和团队的成长,您的工作流也应该不断优化和完善。保持学习新的工具和实践,关注社区的最新发展,这将帮助您构建更加高效和可靠的软件交付流水线。

Happy Coding! 🚀

name: playwright-report

path: playwright-report/

部署

deploy:

name: 部署

runs-on: ubuntu-latest

needs: [frontend, backend, e2e]

if: github.ref == 'refs/heads/main' && success()

复制代码
steps:
- name: Download frontend build
  uses: actions/download-artifact@v3
  with:
    name: frontend-build
    path: frontend-dist/

- name: Deploy frontend to CDN
  run: |
    # 部署前端到 CDN
    echo "Deploying frontend to CDN..."

- name: Deploy backend to Kubernetes
  run: |
    # 部署后端到 K8s
    echo "Deploying backend to Kubernetes..."


### 模板 4:Python Django 项目

```yaml
name: Django CI/CD

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

env:
  PYTHON_VERSION: '3.11'

jobs:
  test:
    name: 测试
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: django_test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Python
      uses: actions/setup-python@v4
      with:
        python-version: ${{ env.PYTHON_VERSION }}
        cache: 'pip'
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
        pip install -r requirements-dev.txt
    
    - name: Run migrations
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_test
      run: python manage.py migrate
    
    - name: Run tests
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_test
      run: |
        coverage run --source='.' manage.py test
        coverage xml
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage.xml

  deploy:
    name: 部署到 Heroku
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Deploy to Heroku
      uses: akhileshns/heroku-deploy@v3.12.14
      with:
        heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
        heroku_app_name: "your-django-app"
        heroku_email: "your-email@example.com"

总结

GitHub Actions 作为现代 CI/CD 的重要工具,为开发团队提供了强大而灵活的自动化能力。通过本指南,您应该能够:

🎯 核心收获

  1. 理解 CI/CD 概念:掌握持续集成和持续部署的基本原理
  2. 熟练使用 GitHub Actions:了解工作流、作业、步骤等核心概念
  3. 实践最佳实践:应用安全性、性能优化和错误处理策略
  4. 解决常见问题:快速诊断和解决工作流中的典型问题

📈 进阶建议

  1. 持续学习:关注 GitHub Actions 的新功能和社区最佳实践
  2. 监控优化:定期审查工作流性能,优化执行时间和资源使用
  3. 安全第一:始终遵循安全最佳实践,保护敏感信息
  4. 团队协作:建立团队 CI/CD 规范,确保一致性

🔗 有用资源

🚀 下一步行动

  1. 选择适合您项目的模板开始实践
  2. 根据项目需求定制工作流
  3. 逐步添加高级功能和优化
  4. 与团队分享经验和最佳实践

记住,优秀的 CI/CD 流程不是一蹴而就的,需要持续改进和优化。从简单开始,逐步完善,最终构建出适合您团队的完美自动化流程。


本指南将持续更新,以反映 GitHub Actions 的最新功能和社区最佳实践。如有问题或建议,欢迎提出反馈。

name: playwright-report

path: playwright-report/

部署

deploy:

name: 部署应用

runs-on: ubuntu-latest

needs: [frontend-ci, backend-ci, integration-test]

if: github.ref == 'refs/heads/main' && success()

复制代码
steps:
- uses: actions/checkout@v4

- name: Download frontend build
  uses: actions/download-artifact@v3
  with:
    name: frontend-build
    path: frontend/dist/

- name: Deploy to AWS
  env:
    AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
    AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
    AWS_REGION: us-east-1
  run: |
    # 部署前端到 S3
    aws s3 sync frontend/dist/ s3://your-frontend-bucket --delete
    
    # 部署后端到 ECS
    aws ecs update-service --cluster your-cluster --service your-service --force-new-deployment


---

## 高级功能和最佳实践

### 矩阵构建策略

```yaml
name: Matrix Build Strategy

on: [push, pull_request]

jobs:
  test:
    name: Test on ${{ matrix.os }} with Node ${{ matrix.node-version }}
    runs-on: ${{ matrix.os }}
    
    strategy:
      # 失败时不停止其他任务
      fail-fast: false
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        node-version: [16, 18, 20]
        # 排除特定组合
        exclude:
          - os: windows-latest
            node-version: 16
        # 包含特定组合
        include:
          - os: ubuntu-latest
            node-version: 21
            experimental: true
    
    # 允许实验性构建失败
    continue-on-error: ${{ matrix.experimental || false }}
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run tests
      run: npm test

条件执行和依赖管理

yaml 复制代码
name: Conditional Execution

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

jobs:
  # 基础检查
  lint:
    name: 代码检查
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Run linting
      run: npm run lint

  # 单元测试
  unit-test:
    name: 单元测试
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Run unit tests
      run: npm run test:unit

  # 集成测试(依赖于前面的任务)
  integration-test:
    name: 集成测试
    runs-on: ubuntu-latest
    needs: [lint, unit-test]
    steps:
    - uses: actions/checkout@v4
    - name: Run integration tests
      run: npm run test:integration

  # 构建(只在主分支)
  build:
    name: 构建应用
    runs-on: ubuntu-latest
    needs: [lint, unit-test]
    if: github.ref == 'refs/heads/main'
    steps:
    - uses: actions/checkout@v4
    - name: Build application
      run: npm run build

  # 部署(只在构建成功后)
  deploy:
    name: 部署应用
    runs-on: ubuntu-latest
    needs: [build, integration-test]
    if: success() && github.ref == 'refs/heads/main'
    environment: production
    steps:
    - name: Deploy to production
      run: echo "Deploying to production..."

  # 通知(总是执行)
  notify:
    name: 发送通知
    runs-on: ubuntu-latest
    needs: [deploy]
    if: always()
    steps:
    - name: Send notification
      env:
        STATUS: ${{ needs.deploy.result }}
      run: |
        if [ "$STATUS" == "success" ]; then
          echo "部署成功!"
        else
          echo "部署失败!"
        fi

缓存策略优化

yaml 复制代码
name: Advanced Caching

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    # Node.js 依赖缓存
    - name: Setup Node.js with cache
      uses: actions/setup-node@v4
      with:
        node-version: '18'
        cache: 'npm'
    
    # 自定义缓存
    - name: Cache node modules
      uses: actions/cache@v3
      with:
        path: |
          ~/.npm
          node_modules
          */*/node_modules
        key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
        restore-keys: |
          ${{ runner.os }}-node-
    
    # 构建缓存
    - name: Cache build output
      uses: actions/cache@v3
      with:
        path: |
          .next/cache
          dist
          build
        key: ${{ runner.os }}-build-${{ github.sha }}
        restore-keys: |
          ${{ runner.os }}-build-
    
    # Docker 层缓存
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Build Docker image with cache
      uses: docker/build-push-action@v5
      with:
        context: .
        cache-from: type=gha
        cache-to: type=gha,mode=max
        tags: myapp:latest

并行任务和工作流复用

yaml 复制代码
# .github/workflows/reusable-test.yml
name: Reusable Test Workflow

on:
  workflow_call:
    inputs:
      node-version:
        required: true
        type: string
      working-directory:
        required: false
        type: string
        default: '.'
    secrets:
      NPM_TOKEN:
        required: false

jobs:
  test:
    runs-on: ubuntu-latest
    defaults:
      run:
        working-directory: ${{ inputs.working-directory }}
    
    steps:
    - uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ inputs.node-version }}
        registry-url: 'https://registry.npmjs.org'
    
    - name: Install dependencies
      env:
        NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
      run: npm ci
    
    - name: Run tests
      run: npm test
yaml 复制代码
# .github/workflows/main.yml
name: Main Workflow

on: [push, pull_request]

jobs:
  # 使用可复用工作流
  test-frontend:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '18'
      working-directory: './frontend'
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
  
  test-backend:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '18'
      working-directory: './backend'
  
  # 并行执行多个任务
  parallel-tasks:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Run parallel commands
      run: |
        # 后台运行多个命令
        npm run lint &
        npm run type-check &
        npm run test:unit &
        
        # 等待所有后台任务完成
        wait

安全性和性能优化

Secrets 管理最佳实践

1. 环境级别的 Secrets
yaml 复制代码
name: Secure Deployment

on:
  push:
    branches: [ main ]

jobs:
  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging
    steps:
    - name: Deploy to staging
      env:
        # 环境特定的 secrets
        API_KEY: ${{ secrets.STAGING_API_KEY }}
        DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
      run: |
        echo "Deploying to staging with secure credentials"

  deploy-production:
    runs-on: ubuntu-latest
    environment: production
    # 需要手动批准
    steps:
    - name: Deploy to production
      env:
        API_KEY: ${{ secrets.PRODUCTION_API_KEY }}
        DATABASE_URL: ${{ secrets.PRODUCTION_DATABASE_URL }}
      run: |
        echo "Deploying to production with secure credentials"
2. 动态 Secrets 引用
yaml 复制代码
jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [staging, production]
    
    steps:
    - name: Deploy to ${{ matrix.environment }}
      env:
        # 动态引用不同环境的 secrets
        API_KEY: ${{ secrets[format('{0}_API_KEY', matrix.environment)] }}
        DB_URL: ${{ secrets[format('{0}_DATABASE_URL', matrix.environment)] }}
      run: |
        echo "Deploying to ${{ matrix.environment }}"

权限最小化原则

yaml 复制代码
name: Minimal Permissions

on: [push, pull_request]

# 全局权限设置
permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-latest
    # 作业级别权限
    permissions:
      contents: read
      checks: write
    steps:
    - uses: actions/checkout@v4
    - name: Run tests
      run: npm test

  publish:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      packages: write
    steps:
    - uses: actions/checkout@v4
    - name: Publish package
      run: npm publish

安全扫描集成

yaml 复制代码
name: Security Scanning

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]
  schedule:
    - cron: '0 2 * * 1'  # 每周一凌晨2点

jobs:
  # 依赖漏洞扫描
  dependency-scan:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Run npm audit
      run: npm audit --audit-level moderate
    
    - name: Snyk security scan
      uses: snyk/actions/node@master
      env:
        SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
      with:
        args: --severity-threshold=high
        command: test

  # 代码安全扫描
  code-scan:
    runs-on: ubuntu-latest
    permissions:
      security-events: write
    steps:
    - uses: actions/checkout@v4
    
    - name: Initialize CodeQL
      uses: github/codeql-action/init@v2
      with:
        languages: javascript, typescript
    
    - name: Autobuild
      uses: github/codeql-action/autobuild@v2
    
    - name: Perform CodeQL Analysis
      uses: github/codeql-action/analyze@v2

  # Docker 镜像安全扫描
  docker-scan:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Build Docker image
      run: docker build -t myapp:latest .
    
    - name: Scan Docker image
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: 'myapp:latest'
        format: 'sarif'
        output: 'trivy-results.sarif'
    
    - name: Upload Trivy scan results
      uses: github/codeql-action/upload-sarif@v2
      with:
        sarif_file: 'trivy-results.sarif'

性能优化策略

1. 并行化优化
yaml 复制代码
name: Performance Optimized

on: [push, pull_request]

jobs:
  # 快速反馈任务
  quick-checks:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Quick lint check
      run: npm run lint:fast
    - name: Type check
      run: npm run type-check

  # 并行测试
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    steps:
    - uses: actions/checkout@v4
    - name: Run test shard ${{ matrix.shard }}
      run: npm run test -- --shard=${{ matrix.shard }}/4

  # 并行构建
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        target: [web, mobile, desktop]
    steps:
    - uses: actions/checkout@v4
    - name: Build ${{ matrix.target }}
      run: npm run build:${{ matrix.target }}
2. 智能缓存策略
yaml 复制代码
name: Smart Caching

on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    # 分层缓存策略
    - name: Cache dependencies
      uses: actions/cache@v3
      with:
        path: node_modules
        key: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }}
        restore-keys: deps-${{ runner.os }}-
    
    - name: Cache build artifacts
      uses: actions/cache@v3
      with:
        path: |
          .next/cache
          dist
        key: build-${{ runner.os }}-${{ github.sha }}
        restore-keys: |
          build-${{ runner.os }}-${{ github.ref_name }}-
          build-${{ runner.os }}-
    
    # 条件性安装
    - name: Install dependencies
      if: steps.cache-deps.outputs.cache-hit != 'true'
      run: npm ci
    
    # 增量构建
    - name: Build application
      run: |
        if [ -d "dist" ]; then
          echo "Using incremental build"
          npm run build:incremental
        else
          echo "Full build required"
          npm run build
        fi

常见问题和解决方案

问题 1:工作流执行时间过长

症状

  • 工作流执行超过 30 分钟
  • 频繁超时失败
  • 资源使用效率低

解决方案

yaml 复制代码
name: Optimized Workflow

on: [push, pull_request]

jobs:
  # 1. 使用并行执行
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        shard: [1, 2, 3, 4]
    steps:
    - uses: actions/checkout@v4
    - name: Run tests in parallel
      run: npm run test -- --shard=${{ matrix.shard }}/4

  # 2. 优化缓存策略
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Restore cache
      uses: actions/cache@v3
      with:
        path: |
          node_modules
          ~/.npm
        key: ${{ runner.os }}-${{ hashFiles('package-lock.json') }}
    
    # 3. 使用更快的包管理器
    - name: Setup pnpm
      uses: pnpm/action-setup@v2
      with:
        version: 8
    
    - name: Install dependencies
      run: pnpm install --frozen-lockfile

  # 4. 条件执行
  deploy:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    steps:
    - name: Deploy only when necessary
      run: echo "Deploying..."

问题 2:Secrets 管理混乱

症状

  • Secrets 命名不规范
  • 环境间 Secrets 混用
  • 安全性问题

解决方案

yaml 复制代码
name: Proper Secrets Management

on: [push]

jobs:
  deploy:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        environment: [staging, production]
    
    environment: ${{ matrix.environment }}
    
    steps:
    - name: Deploy with proper secrets
      env:
        # 使用环境特定的 secrets
        API_KEY: ${{ secrets.API_KEY }}
        DATABASE_URL: ${{ secrets.DATABASE_URL }}
        # 或者使用动态引用
        DYNAMIC_SECRET: ${{ secrets[format('{0}_SECRET', matrix.environment)] }}
      run: |
        echo "Deploying to ${{ matrix.environment }}"
        echo "API Key length: ${#API_KEY}"

Secrets 命名规范

复制代码
# 环境特定
STAGING_API_KEY
PRODUCTION_API_KEY

# 服务特定
GITHUB_TOKEN
DOCKER_REGISTRY_TOKEN
AWS_ACCESS_KEY_ID

# 功能特定
CODECOV_TOKEN
SNYK_TOKEN

问题 3:依赖冲突和版本问题

症状

  • 不同环境构建结果不一致
  • 依赖版本冲突
  • 构建失败

解决方案

yaml 复制代码
name: Dependency Management

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    # 1. 锁定 Node.js 版本
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version-file: '.nvmrc'  # 使用项目指定版本
        cache: 'npm'
    
    # 2. 使用精确的依赖安装
    - name: Install dependencies
      run: |
        # 使用 ci 而不是 install
        npm ci
        # 验证依赖完整性
        npm audit --audit-level moderate
    
    # 3. 版本一致性检查
    - name: Check dependency versions
      run: |
        npm ls --depth=0
        npm outdated || true
    
    # 4. 多版本测试
  multi-version-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [16, 18, 20]
    
    steps:
    - uses: actions/checkout@v4
    - name: Setup Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v4
      with:
        node-version: ${{ matrix.node-version }}
    
    - name: Test compatibility
      run: |
        npm ci
        npm test

问题 4:环境变量和配置管理

症状

  • 环境变量混乱
  • 配置在不同环境不一致
  • 敏感信息泄露

解决方案

yaml 复制代码
name: Environment Management

on: [push]

env:
  # 全局环境变量
  NODE_ENV: production
  LOG_LEVEL: info

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    strategy:
      matrix:
        environment: [staging, production]
    
    environment: ${{ matrix.environment }}
    
    steps:
    - uses: actions/checkout@v4
    
    # 1. 环境特定配置
    - name: Setup environment config
      run: |
        case "${{ matrix.environment }}" in
          staging)
            echo "API_URL=https://api-staging.example.com" >> $GITHUB_ENV
            echo "DEBUG=true" >> $GITHUB_ENV
            ;;
          production)
            echo "API_URL=https://api.example.com" >> $GITHUB_ENV
            echo "DEBUG=false" >> $GITHUB_ENV
            ;;
        esac
    
    # 2. 配置验证
    - name: Validate configuration
      env:
        DATABASE_URL: ${{ secrets.DATABASE_URL }}
      run: |
        # 检查必需的环境变量
        required_vars=("API_URL" "DATABASE_URL" "NODE_ENV")
        for var in "${required_vars[@]}"; do
          if [ -z "${!var}" ]; then
            echo "Error: $var is not set"
            exit 1
          fi
        done
    
    # 3. 安全的配置文件生成
    - name: Generate config file
      env:
        API_KEY: ${{ secrets.API_KEY }}
      run: |
        cat > config.json << EOF
        {
          "environment": "${{ matrix.environment }}",
          "apiUrl": "$API_URL",
          "debug": $DEBUG,
          "version": "${{ github.sha }}"
        }
        EOF
        
        # 不在日志中显示敏感信息
        echo "Config file generated successfully"

问题 5:Docker 构建优化

症状

  • Docker 构建时间过长
  • 镜像体积过大
  • 缓存效率低

解决方案

yaml 复制代码
name: Optimized Docker Build

on: [push]

jobs:
  build:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v4
    
    # 1. 设置 Docker Buildx
    - name: Set up Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    # 2. 登录到镜像仓库
    - name: Login to registry
      uses: docker/login-action@v3
      with:
        registry: ghcr.io
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    # 3. 优化的多阶段构建
    - name: Build and push
      uses: docker/build-push-action@v5
      with:
        context: .
        file: ./Dockerfile.optimized
        platforms: linux/amd64,linux/arm64
        push: true
        tags: |
          ghcr.io/${{ github.repository }}:latest
          ghcr.io/${{ github.repository }}:${{ github.sha }}
        # 使用 GitHub Actions 缓存
        cache-from: type=gha
        cache-to: type=gha,mode=max
        # 构建参数
        build-args: |
          NODE_VERSION=18
          BUILD_DATE=${{ github.event.head_commit.timestamp }}
          VCS_REF=${{ github.sha }}

优化的 Dockerfile

dockerfile 复制代码
# Dockerfile.optimized
FROM node:18-alpine AS base
WORKDIR /app
COPY package*.json ./

FROM base AS deps
RUN npm ci --only=production && npm cache clean --force

FROM base AS build
RUN npm ci
COPY . .
RUN npm run build

FROM node:18-alpine AS runtime
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
COPY package*.json ./

EXPOSE 3000
CMD ["npm", "start"]

实用配置模板

模板 1:React + TypeScript 项目

yaml 复制代码
name: React TypeScript CI/CD

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

env:
  NODE_VERSION: '18'
  CACHE_KEY_PREFIX: 'react-app'

jobs:
  # 代码质量检查
  quality:
    name: 代码质量检查
    runs-on: ubuntu-latest
    
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Type check
      run: npm run type-check
    
    - name: Lint
      run: npm run lint
    
    - name: Format check
      run: npm run format:check
    
    - name: Unit tests
      run: npm run test:coverage
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3
      with:
        file: ./coverage/lcov.info

  # 构建
  build:
    name: 构建应用
    runs-on: ubuntu-latest
    needs: quality
    
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Build
      run: npm run build
    
    - name: Upload build artifacts
      uses: actions/upload-artifact@v3
      with:
        name: build-files
        path: build/
        retention-days: 7

  # 部署
  deploy:
    name: 部署到 Vercel
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    
    - name: Deploy to 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'

模板 2:Node.js API 项目

yaml 复制代码
name: Node.js API CI/CD

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

env:
  NODE_VERSION: '18'
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # 测试
  test:
    name: 测试
    runs-on: ubuntu-latest
    
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: postgres
          POSTGRES_DB: test_db
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 5432:5432
    
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    
    - name: Setup Node.js
      uses: actions/setup-node@v4
      with:
        node-version: ${{ env.NODE_VERSION }}
        cache: 'npm'
    
    - name: Install dependencies
      run: npm ci
    
    - name: Run migrations
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
      run: npm run db:migrate
    
    - name: Run tests
      env:
        DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_db
      run: npm run test:coverage
    
    - name: Upload coverage
      uses: codecov/codecov-action@v3

  # 构建 Docker 镜像
  build:
    name: 构建镜像
    runs-on: ubuntu-latest
    needs: test
    
    steps:
    - name: Checkout
      uses: actions/checkout@v4
    
    - name: Setup Docker Buildx
      uses: docker/setup-buildx-action@v3
    
    - name: Login to registry
      uses: docker/login-action@v3
      with:
        registry: ${{ env.REGISTRY }}
        username: ${{ github.actor }}
        password: ${{ secrets.GITHUB_TOKEN }}
    
    - name: Extract metadata
      id: meta
      uses: docker/metadata-action@v5
      with:
        images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
        tags: |
          type=ref,event=branch
          type=ref,event=pr
          type=sha
    
    - name: Build and push
      uses: docker/build-push-action@v5
      with:
        context: .
        push: true
        tags: ${{ steps.meta.outputs.tags }}
        labels: ${{ steps.meta.outputs.labels }}
        cache-from: type=gha
        cache-to: type=gha,mode=max

  # 部署
  deploy:
    name: 部署
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment: production
    
    steps:
    - name: Deploy to server
      uses: appleboy/ssh-action@v1.0.0
      with:
        host: ${{ secrets.HOST }}
        username: ${{ secrets.USERNAME }}
        key: ${{ secrets.SSH_KEY }}
        script: |
          docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main
          docker stop api || true
          docker rm api || true
          docker run -d \
            --name api \
            --restart unless-stopped \
            -p 3000:3000 \
            -e DATABASE_URL=${{ secrets.DATABASE_URL }} \
            ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:main

本指南涵盖了 GitHub Actions CI/CD 的核心概念、实践案例和最佳实践。通过学习和应用这些知识,您将能够构建高效、安全、可靠的自动化部署流程。

相关推荐
lkbhua莱克瓦248 小时前
Java练习——正则表达式2
java·开发语言·笔记·正则表达式·github·学习方法
A~taoker18 小时前
扣子工作流——测试用例表格生成
功能测试·自动化
ZhiqianXia19 小时前
github 软件安全术语
安全·github
苦学编程的谢20 小时前
Redis_3_Redis介绍+常见命令
数据库·redis·github
FJW0208141 天前
DevOps——CI/CD持续集成与持续交付/部署的理解与部署
运维·ci/cd·devops
Rverdoser1 天前
制作网站的价格一般由什么组成
前端·git·github
叹雪飞花1 天前
借助Github Action实现通过 HTTP 请求触发邮件通知
后端·开源·github
赵文宇1 天前
构建内网离线的"github.com",完美解决内网Go开发依赖
github
逛逛GitHub1 天前
国产首个开源 AI 原生后端平台,这次是真起飞了。
后端·github