GitHub Actions CI/CD 自动化部署完全指南
GitHub Actions CI/CD 自动化部署完全指南
文章目录
- GitHub Actions CI/CD 自动化部署完全指南
- 什么是 CI/CD 和 GitHub Actions
- CI/CD 概念
- GitHub Actions 简介
- 🚀 主要优势
- 📊 使用统计
 
 
- GitHub Actions 核心概念
- 基本组件
- 1. **Workflow(工作流)**
- 2. **Event(事件)**
- 3. **Job(作业)**
- 4. **Step(步骤)**
- 5. **Action(动作)**
- 6. **Runner(运行器)**
 
- 工作流语法结构
 
- 基础工作流配置
- 创建第一个工作流
- 1. 创建工作流文件
- 2. 常用触发事件
- 3. 环境变量配置
 
 
- 前端项目 CI/CD 实践
- React 项目完整工作流
- Vue.js 项目工作流
 
- 后端项目 CI/CD 实践
- Node.js Express 应用
- Python Django 应用
 
- 全栈项目 CI/CD 实践
- Monorepo 项目结构
 
- 安全性和性能优化
- 安全最佳实践
- 1. **Secrets 管理**
- 2. **权限最小化**
- 3. **依赖安全扫描**
- 4. **环境隔离和保护**
 
- 性能优化策略
- 1. **缓存优化**
- 2. **并行执行优化**
- 3. **资源优化**
 
 
- 常见问题和解决方案
- 构建和部署问题
- 1. **依赖安装失败**
- 2. **Docker 构建失败**
- 3. **测试超时或失败**
 
- 权限和安全问题
- 1. **权限被拒绝错误**
- 2. **Secrets 访问问题**
 
- 性能问题
- 1. **构建时间过长**
- 2. **资源限制问题**
 
- 调试技巧
- 1. **启用调试日志**
- 2. **条件调试**
 
 
- 总结
- 关键要点
- 最佳实践总结
- ✅ 推荐做法
- ❌ 避免的做法
 
- 进阶学习路径
- 参考资料
- 官方文档
- 社区资源
- 工具和服务
- 博客和教程
 
 
 
- 部署
- 总结
- 🎯 核心收获
- 📈 进阶建议
- 🔗 有用资源
- 🚀 下一步行动
 
 
- 部署
- 条件执行和依赖管理
- 缓存策略优化
- 并行任务和工作流复用
 
- 安全性和性能优化
- Secrets 管理最佳实践
- 1. 环境级别的 Secrets
- 2. 动态 Secrets 引用
 
- 权限最小化原则
- 安全扫描集成
- 性能优化策略
- 1. 并行化优化
- 2. 智能缓存策略
 
 
- 常见问题和解决方案
- 问题 1:工作流执行时间过长
- 问题 2:Secrets 管理混乱
- 问题 3:依赖冲突和版本问题
- 问题 4:环境变量和配置管理
- 问题 5:Docker 构建优化
 
- 实用配置模板
- 模板 1:React + TypeScript 项目
- 模板 2:Node.js API 项目
 
 
什么是 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(事件)
- 触发工作流的特定活动
- 常见事件:push、pull_request、schedule、workflow_dispatch
3. Job(作业)
- 工作流中的一组步骤
- 在同一个运行器上执行
- 可以并行或串行执行
4. Step(步骤)
- Job 中的单个任务
- 可以运行命令或使用 Action
5. Action(动作)
- 可重用的代码单元
- 可以是自定义的或来自市场
6. Runner(运行器)
- 执行工作流的服务器
- GitHub 提供托管运行器,也可以自托管
工作流语法结构
name: 工作流名称# 触发条件
on:push:branches: [ main, develop ]pull_request:branches: [ main ]# 环境变量
env:NODE_VERSION: '18'# 作业定义
jobs:job-name:runs-on: ubuntu-lateststeps:- name: 步骤名称uses: actions/checkout@v4- name: 另一个步骤run: echo "Hello World"
基础工作流配置
创建第一个工作流
1. 创建工作流文件
在项目根目录创建 .github/workflows/ci.yml:
name: Basic CI# 触发条件:推送到 main 分支或创建 PR
on:push:branches: [ main ]pull_request:branches: [ main ]jobs:test:name: 运行测试runs-on: ubuntu-lateststeps:# 检出代码- name: Checkout codeuses: actions/checkout@v4# 设置 Node.js 环境- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: '18'cache: 'npm'# 安装依赖- name: Install dependenciesrun: npm ci# 运行测试- name: Run testsrun: npm test# 运行代码检查- name: Run lintingrun: npm run lint
2. 常用触发事件
on:# 推送到指定分支push:branches: [ main, develop ]paths:- 'src/**'- 'package.json'# Pull Requestpull_request:branches: [ main ]types: [opened, synchronize, reopened]# 定时执行schedule:- cron: '0 2 * * *'  # 每天凌晨2点# 手动触发workflow_dispatch:inputs:environment:description: '部署环境'required: truedefault: 'staging'type: choiceoptions:- staging- production# 发布 Releaserelease:types: [published]
3. 环境变量配置
env:# 全局环境变量NODE_VERSION: '18'REGISTRY_URL: 'https://registry.npmjs.org'jobs:build:runs-on: ubuntu-latestenv:# Job 级别环境变量BUILD_ENV: productionsteps:- name: Build applicationenv:# 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 项目完整工作流
name: React App CI/CDon: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-lateststeps:- name: Checkout codeuses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'registry-url: ${{ env.REGISTRY_URL }}- name: Install dependenciesrun: npm ci- name: Run ESLintrun: npm run lint- name: Run Prettier checkrun: npm run format:check- name: Run type checkrun: npm run type-check- name: Run tests with coveragerun: npm run test:coverage- name: Upload coverage to Codecovuses: codecov/codecov-action@v3with:file: ./coverage/lcov.infoflags: unittestsname: codecov-umbrella# 构建应用build:name: 构建应用runs-on: ubuntu-latestneeds: quality-checkstrategy:matrix:environment: [staging, production]steps:- name: Checkout codeuses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'- name: Install dependenciesrun: 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 artifactsuses: actions/upload-artifact@v3with:name: build-${{ matrix.environment }}path: build/retention-days: 7# 部署到 Verceldeploy-vercel:name: 部署到 Vercelruns-on: ubuntu-latestneeds: buildif: github.ref == 'refs/heads/main'steps:- name: Checkout codeuses: actions/checkout@v4- name: Download build artifactsuses: actions/download-artifact@v3with:name: build-productionpath: build/- name: Deploy to Verceluses: amondnet/vercel-action@v25with:vercel-token: ${{ secrets.VERCEL_TOKEN }}vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}working-directory: ./vercel-args: '--prod'# 部署到 Netlifydeploy-netlify:name: 部署到 Netlifyruns-on: ubuntu-latestneeds: buildif: github.ref == 'refs/heads/develop'steps:- name: Download build artifactsuses: actions/download-artifact@v3with:name: build-stagingpath: build/- name: Deploy to Netlifyuses: nwtgck/actions-netlify@v2.0with:publish-dir: './build'production-branch: maingithub-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 项目工作流
name: Vue.js App CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]jobs:test-and-build:name: 测试和构建runs-on: ubuntu-lateststrategy:matrix:node-version: [16, 18, 20]steps:- uses: actions/checkout@v4- name: Setup Node.js ${{ matrix.node-version }}uses: actions/setup-node@v4with:node-version: ${{ matrix.node-version }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Run unit testsrun: npm run test:unit- name: Run e2e testsrun: npm run test:e2e:headless- name: Build applicationrun: npm run build- name: Upload build artifactsif: matrix.node-version == 18uses: actions/upload-artifact@v3with:name: vue-buildpath: dist/deploy:name: 部署应用runs-on: ubuntu-latestneeds: test-and-buildif: github.ref == 'refs/heads/main'steps:- name: Download build artifactsuses: actions/download-artifact@v3with:name: vue-buildpath: dist/- name: Deploy to GitHub Pagesuses: peaceiris/actions-gh-pages@v3with:github_token: ${{ secrets.GITHUB_TOKEN }}publish_dir: ./dist
后端项目 CI/CD 实践
Node.js Express 应用
name: Node.js Express API CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]env:NODE_VERSION: '18'DOCKER_REGISTRY: 'ghcr.io'jobs:# 测试阶段test:name: 运行测试runs-on: ubuntu-latestservices:# PostgreSQL 服务postgres:image: postgres:15env:POSTGRES_PASSWORD: postgresPOSTGRES_DB: test_dboptions: >---health-cmd pg_isready--health-interval 10s--health-timeout 5s--health-retries 5ports:- 5432:5432# Redis 服务redis:image: redis:7options: >---health-cmd "redis-cli ping"--health-interval 10s--health-timeout 5s--health-retries 5ports:- 6379:6379steps:- name: Checkout codeuses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Run database migrationsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_dbrun: npm run db:migrate- name: Run unit testsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_dbREDIS_URL: redis://localhost:6379run: npm run test- name: Run integration testsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_dbREDIS_URL: redis://localhost:6379run: npm run test:integration- name: Generate test coveragerun: npm run test:coverage- name: Upload coverage reportsuses: codecov/codecov-action@v3with:file: ./coverage/lcov.info# 安全扫描security-scan:name: 安全扫描runs-on: ubuntu-lateststeps:- name: Checkout codeuses: actions/checkout@v4- name: Run npm auditrun: npm audit --audit-level moderate- name: Run Snyk security scanuses: snyk/actions/node@masterenv:SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}with:args: --severity-threshold=high# 构建 Docker 镜像build-docker:name: 构建 Docker 镜像runs-on: ubuntu-latestneeds: [test, security-scan]steps:- name: Checkout codeuses: actions/checkout@v4- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3- name: Login to Container Registryuses: docker/login-action@v3with:registry: ${{ env.DOCKER_REGISTRY }}username: ${{ github.actor }}password: ${{ secrets.GITHUB_TOKEN }}- name: Extract metadataid: metauses: docker/metadata-action@v5with:images: ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}tags: |type=ref,event=branchtype=ref,event=prtype=sha,prefix={{branch}}-type=raw,value=latest,enable={{is_default_branch}}- name: Build and push Docker imageuses: docker/build-push-action@v5with:context: .platforms: linux/amd64,linux/arm64push: truetags: ${{ steps.meta.outputs.tags }}labels: ${{ steps.meta.outputs.labels }}cache-from: type=ghacache-to: type=gha,mode=max# 部署到 stagingdeploy-staging:name: 部署到 Stagingruns-on: ubuntu-latestneeds: build-dockerif: github.ref == 'refs/heads/develop'environment: stagingsteps:- name: Deploy to staging serveruses: appleboy/ssh-action@v1.0.0with:host: ${{ secrets.STAGING_HOST }}username: ${{ secrets.STAGING_USER }}key: ${{ secrets.STAGING_SSH_KEY }}script: |docker pull ${{ env.DOCKER_REGISTRY }}/${{ github.repository }}:developdocker stop api-staging || truedocker rm api-staging || truedocker 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# 部署到 productiondeploy-production:name: 部署到 Productionruns-on: ubuntu-latestneeds: build-dockerif: github.ref == 'refs/heads/main'environment: productionsteps:- name: Deploy to Kubernetesuses: azure/k8s-deploy@v1with:manifests: |k8s/deployment.yamlk8s/service.yamlimages: |${{ env.DOCKER_REGISTRY }}/${{ github.repository }}:latestkubeconfig: ${{ secrets.KUBE_CONFIG }}
Python Django 应用
name: Django App CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]jobs:test:name: 测试 Django 应用runs-on: ubuntu-lateststrategy:matrix:python-version: [3.9, 3.10, 3.11]services:postgres:image: postgres:15env:POSTGRES_PASSWORD: postgresPOSTGRES_DB: django_testoptions: >---health-cmd pg_isready--health-interval 10s--health-timeout 5s--health-retries 5ports:- 5432:5432steps:- uses: actions/checkout@v4- name: Set up Python ${{ matrix.python-version }}uses: actions/setup-python@v4with:python-version: ${{ matrix.python-version }}- name: Install dependenciesrun: |python -m pip install --upgrade pippip install -r requirements.txtpip install -r requirements-dev.txt- name: Run migrationsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_testrun: python manage.py migrate- name: Run testsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_testrun: |python manage.py testcoverage run --source='.' manage.py testcoverage xml- name: Upload coverage to Codecovuses: codecov/codecov-action@v3with:file: ./coverage.xmldeploy:name: 部署到 Herokuruns-on: ubuntu-latestneeds: testif: github.ref == 'refs/heads/main'steps:- uses: actions/checkout@v4- name: Deploy to Herokuuses: akhileshns/heroku-deploy@v3.12.14with:heroku_api_key: ${{ secrets.HEROKU_API_KEY }}heroku_app_name: "your-django-app"heroku_email: "your-email@example.com"
全栈项目 CI/CD 实践
Monorepo 项目结构
name: Full Stack Monorepo CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]env:NODE_VERSION: '18'PYTHON_VERSION: '3.11'jobs:# 检测变更detect-changes:name: 检测文件变更runs-on: ubuntu-latestoutputs:frontend: ${{ steps.changes.outputs.frontend }}backend: ${{ steps.changes.outputs.backend }}shared: ${{ steps.changes.outputs.shared }}steps:- uses: actions/checkout@v4- uses: dorny/paths-filter@v2id: changeswith:filters: |frontend:- 'frontend/**'- 'shared/**'backend:- 'backend/**'- 'shared/**'shared:- 'shared/**'# 前端测试和构建frontend-ci:name: 前端 CIruns-on: ubuntu-latestneeds: detect-changesif: needs.detect-changes.outputs.frontend == 'true'defaults:run:working-directory: ./frontendsteps:- uses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'cache-dependency-path: frontend/package-lock.json- name: Install dependenciesrun: npm ci- name: Run testsrun: npm test- name: Build applicationrun: npm run build- name: Upload build artifactsuses: actions/upload-artifact@v3with:name: frontend-buildpath: frontend/dist/# 后端测试backend-ci:name: 后端 CIruns-on: ubuntu-latestneeds: detect-changesif: needs.detect-changes.outputs.backend == 'true'defaults:run:working-directory: ./backendservices:postgres:image: postgres:15env:POSTGRES_PASSWORD: postgresPOSTGRES_DB: test_dboptions: >---health-cmd pg_isready--health-interval 10s--health-timeout 5s--health-retries 5ports:- 5432:5432steps:- uses: actions/checkout@v4- name: Setup Pythonuses: actions/setup-python@v4with:python-version: ${{ env.PYTHON_VERSION }}- name: Install dependenciesrun: |python -m pip install --upgrade pippip install -r requirements.txt- name: Run testsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_dbrun: pytest# 集成测试integration-test:name: 集成测试runs-on: ubuntu-latestneeds: [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.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}- name: Install Playwrightrun: |npm install -g @playwright/testnpx playwright install- name: Start services with Docker Composerun: docker-compose -f docker-compose.test.yml up -d- name: Wait for servicesrun: |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 testsrun: npx playwright test- name: Upload test resultsuses: actions/upload-artifact@v3if: always()with:name: playwright-reportpath: playwright-report/# 部署deploy:name: 部署runs-on: ubuntu-latestneeds: [frontend, backend, e2e]if: github.ref == 'refs/heads/main' && success()steps:- name: Download frontend builduses: actions/download-artifact@v3with:name: frontend-buildpath: frontend-dist/- name: Deploy frontend to CDNrun: |# 部署前端到 CDNecho "Deploying frontend to CDN..."- name: Deploy backend to Kubernetesrun: |# 部署后端到 K8secho "Deploying backend to Kubernetes..."
安全性和性能优化
安全最佳实践
1. Secrets 管理
name: Secure CI/CDon:push:branches: [ main ]jobs:secure-build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# ✅ 正确的 secrets 使用- name: Configure AWS credentialsuses: aws-actions/configure-aws-credentials@v4with: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 secretsenv:API_KEY: ${{ secrets.API_KEY }}DATABASE_URL: ${{ secrets.DATABASE_URL }}run: |# 使用环境变量而不是直接引用 secrets./deploy.sh
2. 权限最小化
name: Minimal Permissionson:push:branches: [ main ]# 设置最小权限
permissions:contents: readpackages: writesecurity-events: writejobs:build:runs-on: ubuntu-latest# Job 级别权限覆盖permissions:contents: readpackages: writesteps:- uses: actions/checkout@v4- name: Build and push Docker imageuses: docker/build-push-action@v5with:context: .push: truetags: ghcr.io/${{ github.repository }}:latest
3. 依赖安全扫描
name: Security Scanningon:push:branches: [ main ]pull_request:branches: [ main ]schedule:- cron: '0 6 * * 1'  # 每周一早上6点jobs:security-scan:name: 安全扫描runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# npm 审计- name: Run npm auditrun: |npm audit --audit-level moderatenpm audit fix --dry-run# Snyk 安全扫描- name: Run Snyk to check for vulnerabilitiesuses: snyk/actions/node@masterenv:SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}with:args: --severity-threshold=high --fail-on=upgradable# CodeQL 代码分析- name: Initialize CodeQLuses: github/codeql-action/init@v2with:languages: javascript, typescript- name: Perform CodeQL Analysisuses: github/codeql-action/analyze@v2# 容器镜像扫描- name: Run Trivy vulnerability scanneruses: aquasecurity/trivy-action@masterwith:image-ref: 'myapp:latest'format: 'sarif'output: 'trivy-results.sarif'- name: Upload Trivy scan resultsuses: github/codeql-action/upload-sarif@v2with:sarif_file: 'trivy-results.sarif'
4. 环境隔离和保护
name: Environment Protectionon:push:branches: [ main, develop ]jobs:deploy-staging:name: 部署到 Stagingruns-on: ubuntu-latestenvironment: stagingif: github.ref == 'refs/heads/develop'steps:- name: Deploy to stagingrun: echo "Deploying to staging environment"deploy-production:name: 部署到 Productionruns-on: ubuntu-latestenvironment: name: productionurl: https://myapp.comif: github.ref == 'refs/heads/main'steps:- name: Deploy to productionrun: echo "Deploying to production environment"
性能优化策略
1. 缓存优化
name: Optimized Cachingon:push:branches: [ main ]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# Node.js 依赖缓存- name: Setup Node.js with cacheuses: actions/setup-node@v4with:node-version: '18'cache: 'npm'cache-dependency-path: |package-lock.jsonfrontend/package-lock.jsonbackend/package-lock.json# 自定义缓存- name: Cache node modulesuses: actions/cache@v3with:path: |~/.npmnode_modules*/node_moduleskey: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}restore-keys: |${{ runner.os }}-node-# Docker 层缓存- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3- name: Build with cacheuses: docker/build-push-action@v5with:context: .cache-from: type=ghacache-to: type=gha,mode=maxpush: truetags: myapp:latest
2. 并行执行优化
name: Parallel Executionon:push:branches: [ main ]jobs:# 并行测试矩阵test:name: 测试runs-on: ubuntu-lateststrategy: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@v4with:node-version: ${{ matrix.node-version }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Run ${{ matrix.test-suite }} testsrun: npm run test:${{ matrix.test-suite }}# 并行构建不同平台build:name: 构建runs-on: ubuntu-latestneeds: teststrategy:matrix:platform: [linux/amd64, linux/arm64]steps:- uses: actions/checkout@v4- name: Set up QEMUuses: docker/setup-qemu-action@v3- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3- name: Build for ${{ matrix.platform }}uses: docker/build-push-action@v5with:context: .platforms: ${{ matrix.platform }}push: truetags: myapp:${{ matrix.platform }}
3. 资源优化
name: Resource Optimizationon:push:branches: [ main ]jobs:optimized-build:name: 优化构建runs-on: ubuntu-latest# 设置超时时间timeout-minutes: 30steps:- uses: actions/checkout@v4with:# 浅克隆以减少下载时间fetch-depth: 1# 只在需要时安装依赖- name: Check if dependencies changeduses: dorny/paths-filter@v2id: changeswith:filters: |deps:- 'package*.json'- 'yarn.lock'- name: Setup Node.jsif: steps.changes.outputs.deps == 'true'uses: actions/setup-node@v4with:node-version: '18'cache: 'npm'- name: Install dependenciesif: steps.changes.outputs.deps == 'true'run: npm ci --prefer-offline --no-audit# 条件执行构建- name: Build applicationif: steps.changes.outputs.deps == 'true' || github.event_name == 'push'run: npm run build
常见问题和解决方案
构建和部署问题
1. 依赖安装失败
问题描述:npm ci 或 npm install 失败
常见原因和解决方案:
# 解决方案 1:清理缓存
- name: Clear npm cacherun: npm cache clean --force- name: Install dependenciesrun: npm ci# 解决方案 2:使用不同的 registry
- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: '18'registry-url: 'https://registry.npmmirror.com'# 解决方案 3:忽略可选依赖
- name: Install dependenciesrun: npm ci --no-optional# 解决方案 4:增加超时时间
- name: Install dependenciesrun: npm ci --timeout=300000
2. Docker 构建失败
问题描述:Docker 镜像构建过程中出错
# 解决方案 1:多阶段构建优化
# Dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --forceFROM 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 imageuses: docker/build-push-action@v5with:context: .push: truetags: myapp:latestbuild-args: |BUILDKIT_INLINE_CACHE=1cache-from: type=ghacache-to: type=gha,mode=max
3. 测试超时或失败
# 解决方案 1:增加测试超时时间
- name: Run testsrun: npm testtimeout-minutes: 10# 解决方案 2:并行测试
- name: Run tests in parallelrun: npm test -- --maxWorkers=2# 解决方案 3:重试机制
- name: Run tests with retryuses: nick-invision/retry@v2with:timeout_minutes: 5max_attempts: 3command: npm test
权限和安全问题
1. 权限被拒绝错误
# 问题:Permission denied
# 解决方案:设置正确的权限
permissions:contents: readpackages: writedeployments: write# 或者在 job 级别设置
jobs:deploy:runs-on: ubuntu-latestpermissions:contents: readpackages: writesteps:# ...
2. Secrets 访问问题
# 问题:无法访问 secrets
# 解决方案 1:检查 secrets 名称
- name: Use secretenv:API_KEY: ${{ secrets.API_KEY }}  # 确保名称正确run: echo "Using API key"# 解决方案 2:环境级别的 secrets
jobs:deploy:environment: production  # 使用环境级别的 secretssteps:- name: Deployenv:DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}run: ./deploy.sh
性能问题
1. 构建时间过长
# 解决方案 1:使用缓存
- name: Cache dependenciesuses: actions/cache@v3with:path: ~/.npmkey: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}# 解决方案 2:并行构建
strategy:matrix:component: [frontend, backend, api]max-parallel: 3# 解决方案 3:条件执行
- name: Build only if changedif: steps.changes.outputs.src == 'true'run: npm run build
2. 资源限制问题
# 解决方案 1:使用更大的运行器
jobs:build:runs-on: ubuntu-latest-4-cores  # 使用更多 CPU 核心# 解决方案 2:优化内存使用
- name: Build with memory optimizationrun: |export NODE_OPTIONS="--max-old-space-size=4096"npm run build
调试技巧
1. 启用调试日志
# 启用 Actions 调试
- name: Debug informationrun: |echo "Runner OS: ${{ runner.os }}"echo "GitHub ref: ${{ github.ref }}"echo "Event name: ${{ github.event_name }}"env# 启用 npm 调试
- name: Install with debugrun: npm ci --loglevel verbose# 启用 Docker 调试
- name: Build Docker with debugrun: |export DOCKER_BUILDKIT=1export BUILDKIT_PROGRESS=plaindocker build --progress=plain .
2. 条件调试
- name: Debug on failureif: failure()run: |echo "Build failed, collecting debug info..."ls -lacat package.jsonnpm ls --depth=0
总结
关键要点
- 渐进式采用:从简单的 CI 开始,逐步添加 CD 功能
- 安全第一:始终遵循安全最佳实践,保护敏感信息
- 性能优化:合理使用缓存和并行执行提高效率
- 监控和反馈:建立完善的监控和通知机制
- 文档化:维护清晰的工作流文档和最佳实践
最佳实践总结
✅ 推荐做法
- 使用语义化的工作流和作业名称
- 合理设置触发条件,避免不必要的执行
- 充分利用缓存机制提高构建速度
- 实施全面的测试策略(单元测试、集成测试、E2E 测试)
- 使用环境保护和审批流程
- 定期更新 Actions 版本
- 监控工作流执行时间和成本
❌ 避免的做法
- 在日志中暴露敏感信息
- 使用过于宽泛的权限
- 忽略安全扫描和依赖更新
- 创建过于复杂的单一工作流
- 缺乏错误处理和重试机制
- 不使用环境变量管理配置
进阶学习路径
-  基础阶段 - 掌握 YAML 语法和 GitHub Actions 基本概念
- 创建简单的 CI 工作流
- 学习常用的官方 Actions
 
-  中级阶段 - 实现完整的 CI/CD 流水线
- 掌握矩阵构建和并行执行
- 学习 Docker 集成和容器化部署
 
-  高级阶段 - 创建自定义 Actions
- 实现复杂的部署策略(蓝绿部署、金丝雀发布)
- 集成监控和可观测性工具
 
参考资料
官方文档
- GitHub Actions 官方文档
- 工作流语法参考
- Actions 市场
社区资源
- Awesome GitHub Actions
- GitHub Actions 最佳实践
- Actions 示例仓库
工具和服务
- Act - 本地运行 GitHub Actions
- GitHub Actions Toolkit
- Dependabot - 依赖更新自动化
博客和教程
- GitHub Blog - Actions 相关文章
- DevOps 最佳实践指南
- CI/CD 模式和实践
结语
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 builduses: actions/download-artifact@v3with:name: frontend-buildpath: frontend-dist/- name: Deploy frontend to CDNrun: |# 部署前端到 CDNecho "Deploying frontend to CDN..."- name: Deploy backend to Kubernetesrun: |# 部署后端到 K8secho "Deploying backend to Kubernetes..."
### 模板 4:Python Django 项目```yaml
name: Django CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]env:PYTHON_VERSION: '3.11'jobs:test:name: 测试runs-on: ubuntu-latestservices:postgres:image: postgres:15env:POSTGRES_PASSWORD: postgresPOSTGRES_DB: django_testoptions: >---health-cmd pg_isready--health-interval 10s--health-timeout 5s--health-retries 5ports:- 5432:5432steps:- uses: actions/checkout@v4- name: Setup Pythonuses: actions/setup-python@v4with:python-version: ${{ env.PYTHON_VERSION }}cache: 'pip'- name: Install dependenciesrun: |python -m pip install --upgrade pippip install -r requirements.txtpip install -r requirements-dev.txt- name: Run migrationsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_testrun: python manage.py migrate- name: Run testsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/django_testrun: |coverage run --source='.' manage.py testcoverage xml- name: Upload coverageuses: codecov/codecov-action@v3with:file: ./coverage.xmldeploy:name: 部署到 Herokuruns-on: ubuntu-latestneeds: testif: github.ref == 'refs/heads/main'steps:- uses: actions/checkout@v4- name: Deploy to Herokuuses: akhileshns/heroku-deploy@v3.12.14with:heroku_api_key: ${{ secrets.HEROKU_API_KEY }}heroku_app_name: "your-django-app"heroku_email: "your-email@example.com"
总结
GitHub Actions 作为现代 CI/CD 的重要工具,为开发团队提供了强大而灵活的自动化能力。通过本指南,您应该能够:
🎯 核心收获
- 理解 CI/CD 概念:掌握持续集成和持续部署的基本原理
- 熟练使用 GitHub Actions:了解工作流、作业、步骤等核心概念
- 实践最佳实践:应用安全性、性能优化和错误处理策略
- 解决常见问题:快速诊断和解决工作流中的典型问题
📈 进阶建议
- 持续学习:关注 GitHub Actions 的新功能和社区最佳实践
- 监控优化:定期审查工作流性能,优化执行时间和资源使用
- 安全第一:始终遵循安全最佳实践,保护敏感信息
- 团队协作:建立团队 CI/CD 规范,确保一致性
🔗 有用资源
- GitHub Actions 官方文档
- GitHub Actions 市场
- Awesome GitHub Actions
- GitHub Actions 社区论坛
🚀 下一步行动
- 选择适合您项目的模板开始实践
- 根据项目需求定制工作流
- 逐步添加高级功能和优化
- 与团队分享经验和最佳实践
记住,优秀的 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 builduses: actions/download-artifact@v3with:name: frontend-buildpath: frontend/dist/- name: Deploy to AWSenv:AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}AWS_REGION: us-east-1run: |# 部署前端到 S3aws s3 sync frontend/dist/ s3://your-frontend-bucket --delete# 部署后端到 ECSaws ecs update-service --cluster your-cluster --service your-service --force-new-deployment
---## 高级功能和最佳实践### 矩阵构建策略```yaml
name: Matrix Build Strategyon: [push, pull_request]jobs:test:name: Test on ${{ matrix.os }} with Node ${{ matrix.node-version }}runs-on: ${{ matrix.os }}strategy:# 失败时不停止其他任务fail-fast: falsematrix:os: [ubuntu-latest, windows-latest, macos-latest]node-version: [16, 18, 20]# 排除特定组合exclude:- os: windows-latestnode-version: 16# 包含特定组合include:- os: ubuntu-latestnode-version: 21experimental: true# 允许实验性构建失败continue-on-error: ${{ matrix.experimental || false }}steps:- uses: actions/checkout@v4- name: Setup Node.js ${{ matrix.node-version }}uses: actions/setup-node@v4with:node-version: ${{ matrix.node-version }}- name: Install dependenciesrun: npm ci- name: Run testsrun: npm test
条件执行和依赖管理
name: Conditional Executionon:push:branches: [ main ]pull_request:branches: [ main ]jobs:# 基础检查lint:name: 代码检查runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Run lintingrun: npm run lint# 单元测试unit-test:name: 单元测试runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Run unit testsrun: npm run test:unit# 集成测试(依赖于前面的任务)integration-test:name: 集成测试runs-on: ubuntu-latestneeds: [lint, unit-test]steps:- uses: actions/checkout@v4- name: Run integration testsrun: npm run test:integration# 构建(只在主分支)build:name: 构建应用runs-on: ubuntu-latestneeds: [lint, unit-test]if: github.ref == 'refs/heads/main'steps:- uses: actions/checkout@v4- name: Build applicationrun: npm run build# 部署(只在构建成功后)deploy:name: 部署应用runs-on: ubuntu-latestneeds: [build, integration-test]if: success() && github.ref == 'refs/heads/main'environment: productionsteps:- name: Deploy to productionrun: echo "Deploying to production..."# 通知(总是执行)notify:name: 发送通知runs-on: ubuntu-latestneeds: [deploy]if: always()steps:- name: Send notificationenv:STATUS: ${{ needs.deploy.result }}run: |if [ "$STATUS" == "success" ]; thenecho "部署成功!"elseecho "部署失败!"fi
缓存策略优化
name: Advanced Cachingon: [push, pull_request]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# Node.js 依赖缓存- name: Setup Node.js with cacheuses: actions/setup-node@v4with:node-version: '18'cache: 'npm'# 自定义缓存- name: Cache node modulesuses: actions/cache@v3with:path: |~/.npmnode_modules*/*/node_moduleskey: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}restore-keys: |${{ runner.os }}-node-# 构建缓存- name: Cache build outputuses: actions/cache@v3with:path: |.next/cachedistbuildkey: ${{ runner.os }}-build-${{ github.sha }}restore-keys: |${{ runner.os }}-build-# Docker 层缓存- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3- name: Build Docker image with cacheuses: docker/build-push-action@v5with:context: .cache-from: type=ghacache-to: type=gha,mode=maxtags: myapp:latest
并行任务和工作流复用
# .github/workflows/reusable-test.yml
name: Reusable Test Workflowon:workflow_call:inputs:node-version:required: truetype: stringworking-directory:required: falsetype: stringdefault: '.'secrets:NPM_TOKEN:required: falsejobs:test:runs-on: ubuntu-latestdefaults:run:working-directory: ${{ inputs.working-directory }}steps:- uses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ inputs.node-version }}registry-url: 'https://registry.npmjs.org'- name: Install dependenciesenv:NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}run: npm ci- name: Run testsrun: npm test
# .github/workflows/main.yml
name: Main Workflowon: [push, pull_request]jobs:# 使用可复用工作流test-frontend:uses: ./.github/workflows/reusable-test.ymlwith:node-version: '18'working-directory: './frontend'secrets:NPM_TOKEN: ${{ secrets.NPM_TOKEN }}test-backend:uses: ./.github/workflows/reusable-test.ymlwith:node-version: '18'working-directory: './backend'# 并行执行多个任务parallel-tasks:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Run parallel commandsrun: |# 后台运行多个命令npm run lint &npm run type-check &npm run test:unit &# 等待所有后台任务完成wait
安全性和性能优化
Secrets 管理最佳实践
1. 环境级别的 Secrets
name: Secure Deploymenton:push:branches: [ main ]jobs:deploy-staging:runs-on: ubuntu-latestenvironment: stagingsteps:- name: Deploy to stagingenv:# 环境特定的 secretsAPI_KEY: ${{ secrets.STAGING_API_KEY }}DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}run: |echo "Deploying to staging with secure credentials"deploy-production:runs-on: ubuntu-latestenvironment: production# 需要手动批准steps:- name: Deploy to productionenv:API_KEY: ${{ secrets.PRODUCTION_API_KEY }}DATABASE_URL: ${{ secrets.PRODUCTION_DATABASE_URL }}run: |echo "Deploying to production with secure credentials"
2. 动态 Secrets 引用
jobs:deploy:runs-on: ubuntu-lateststrategy:matrix:environment: [staging, production]steps:- name: Deploy to ${{ matrix.environment }}env:# 动态引用不同环境的 secretsAPI_KEY: ${{ secrets[format('{0}_API_KEY', matrix.environment)] }}DB_URL: ${{ secrets[format('{0}_DATABASE_URL', matrix.environment)] }}run: |echo "Deploying to ${{ matrix.environment }}"
权限最小化原则
name: Minimal Permissionson: [push, pull_request]# 全局权限设置
permissions:contents: readjobs:test:runs-on: ubuntu-latest# 作业级别权限permissions:contents: readchecks: writesteps:- uses: actions/checkout@v4- name: Run testsrun: npm testpublish:runs-on: ubuntu-latestif: github.ref == 'refs/heads/main'permissions:contents: readpackages: writesteps:- uses: actions/checkout@v4- name: Publish packagerun: npm publish
安全扫描集成
name: Security Scanningon:push:branches: [ main ]pull_request:branches: [ main ]schedule:- cron: '0 2 * * 1'  # 每周一凌晨2点jobs:# 依赖漏洞扫描dependency-scan:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Run npm auditrun: npm audit --audit-level moderate- name: Snyk security scanuses: snyk/actions/node@masterenv:SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}with:args: --severity-threshold=highcommand: test# 代码安全扫描code-scan:runs-on: ubuntu-latestpermissions:security-events: writesteps:- uses: actions/checkout@v4- name: Initialize CodeQLuses: github/codeql-action/init@v2with:languages: javascript, typescript- name: Autobuilduses: github/codeql-action/autobuild@v2- name: Perform CodeQL Analysisuses: github/codeql-action/analyze@v2# Docker 镜像安全扫描docker-scan:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Build Docker imagerun: docker build -t myapp:latest .- name: Scan Docker imageuses: aquasecurity/trivy-action@masterwith:image-ref: 'myapp:latest'format: 'sarif'output: 'trivy-results.sarif'- name: Upload Trivy scan resultsuses: github/codeql-action/upload-sarif@v2with:sarif_file: 'trivy-results.sarif'
性能优化策略
1. 并行化优化
name: Performance Optimizedon: [push, pull_request]jobs:# 快速反馈任务quick-checks:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Quick lint checkrun: npm run lint:fast- name: Type checkrun: npm run type-check# 并行测试test:runs-on: ubuntu-lateststrategy: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-lateststrategy:matrix:target: [web, mobile, desktop]steps:- uses: actions/checkout@v4- name: Build ${{ matrix.target }}run: npm run build:${{ matrix.target }}
2. 智能缓存策略
name: Smart Cachingon: [push, pull_request]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# 分层缓存策略- name: Cache dependenciesuses: actions/cache@v3with:path: node_moduleskey: deps-${{ runner.os }}-${{ hashFiles('package-lock.json') }}restore-keys: deps-${{ runner.os }}-- name: Cache build artifactsuses: actions/cache@v3with:path: |.next/cachedistkey: build-${{ runner.os }}-${{ github.sha }}restore-keys: |build-${{ runner.os }}-${{ github.ref_name }}-build-${{ runner.os }}-# 条件性安装- name: Install dependenciesif: steps.cache-deps.outputs.cache-hit != 'true'run: npm ci# 增量构建- name: Build applicationrun: |if [ -d "dist" ]; thenecho "Using incremental build"npm run build:incrementalelseecho "Full build required"npm run buildfi
常见问题和解决方案
问题 1:工作流执行时间过长
症状:
- 工作流执行超过 30 分钟
- 频繁超时失败
- 资源使用效率低
解决方案:
name: Optimized Workflowon: [push, pull_request]jobs:# 1. 使用并行执行test:runs-on: ubuntu-lateststrategy:matrix:shard: [1, 2, 3, 4]steps:- uses: actions/checkout@v4- name: Run tests in parallelrun: npm run test -- --shard=${{ matrix.shard }}/4# 2. 优化缓存策略build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4- name: Restore cacheuses: actions/cache@v3with:path: |node_modules~/.npmkey: ${{ runner.os }}-${{ hashFiles('package-lock.json') }}# 3. 使用更快的包管理器- name: Setup pnpmuses: pnpm/action-setup@v2with:version: 8- name: Install dependenciesrun: pnpm install --frozen-lockfile# 4. 条件执行deploy:runs-on: ubuntu-latestif: github.ref == 'refs/heads/main' && github.event_name == 'push'steps:- name: Deploy only when necessaryrun: echo "Deploying..."
问题 2:Secrets 管理混乱
症状:
- Secrets 命名不规范
- 环境间 Secrets 混用
- 安全性问题
解决方案:
name: Proper Secrets Managementon: [push]jobs:deploy:runs-on: ubuntu-lateststrategy:matrix:environment: [staging, production]environment: ${{ matrix.environment }}steps:- name: Deploy with proper secretsenv:# 使用环境特定的 secretsAPI_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:依赖冲突和版本问题
症状:
- 不同环境构建结果不一致
- 依赖版本冲突
- 构建失败
解决方案:
name: Dependency Managementon: [push, pull_request]jobs:test:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# 1. 锁定 Node.js 版本- name: Setup Node.jsuses: actions/setup-node@v4with:node-version-file: '.nvmrc'  # 使用项目指定版本cache: 'npm'# 2. 使用精确的依赖安装- name: Install dependenciesrun: |# 使用 ci 而不是 installnpm ci# 验证依赖完整性npm audit --audit-level moderate# 3. 版本一致性检查- name: Check dependency versionsrun: |npm ls --depth=0npm outdated || true# 4. 多版本测试multi-version-test:runs-on: ubuntu-lateststrategy:matrix:node-version: [16, 18, 20]steps:- uses: actions/checkout@v4- name: Setup Node.js ${{ matrix.node-version }}uses: actions/setup-node@v4with:node-version: ${{ matrix.node-version }}- name: Test compatibilityrun: |npm cinpm test
问题 4:环境变量和配置管理
症状:
- 环境变量混乱
- 配置在不同环境不一致
- 敏感信息泄露
解决方案:
name: Environment Managementon: [push]env:# 全局环境变量NODE_ENV: productionLOG_LEVEL: infojobs:deploy:runs-on: ubuntu-lateststrategy:matrix:environment: [staging, production]environment: ${{ matrix.environment }}steps:- uses: actions/checkout@v4# 1. 环境特定配置- name: Setup environment configrun: |case "${{ matrix.environment }}" instaging)echo "API_URL=https://api-staging.example.com" >> $GITHUB_ENVecho "DEBUG=true" >> $GITHUB_ENV;;production)echo "API_URL=https://api.example.com" >> $GITHUB_ENVecho "DEBUG=false" >> $GITHUB_ENV;;esac# 2. 配置验证- name: Validate configurationenv:DATABASE_URL: ${{ secrets.DATABASE_URL }}run: |# 检查必需的环境变量required_vars=("API_URL" "DATABASE_URL" "NODE_ENV")for var in "${required_vars[@]}"; doif [ -z "${!var}" ]; thenecho "Error: $var is not set"exit 1fidone# 3. 安全的配置文件生成- name: Generate config fileenv: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 构建时间过长
- 镜像体积过大
- 缓存效率低
解决方案:
name: Optimized Docker Buildon: [push]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v4# 1. 设置 Docker Buildx- name: Set up Docker Buildxuses: docker/setup-buildx-action@v3# 2. 登录到镜像仓库- name: Login to registryuses: docker/login-action@v3with:registry: ghcr.iousername: ${{ github.actor }}password: ${{ secrets.GITHUB_TOKEN }}# 3. 优化的多阶段构建- name: Build and pushuses: docker/build-push-action@v5with:context: .file: ./Dockerfile.optimizedplatforms: linux/amd64,linux/arm64push: truetags: |ghcr.io/${{ github.repository }}:latestghcr.io/${{ github.repository }}:${{ github.sha }}# 使用 GitHub Actions 缓存cache-from: type=ghacache-to: type=gha,mode=max# 构建参数build-args: |NODE_VERSION=18BUILD_DATE=${{ github.event.head_commit.timestamp }}VCS_REF=${{ github.sha }}
优化的 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 --forceFROM base AS build
RUN npm ci
COPY . .
RUN npm run buildFROM 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 项目
name: React TypeScript CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]env:NODE_VERSION: '18'CACHE_KEY_PREFIX: 'react-app'jobs:# 代码质量检查quality:name: 代码质量检查runs-on: ubuntu-lateststeps:- name: Checkoutuses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Type checkrun: npm run type-check- name: Lintrun: npm run lint- name: Format checkrun: npm run format:check- name: Unit testsrun: npm run test:coverage- name: Upload coverageuses: codecov/codecov-action@v3with:file: ./coverage/lcov.info# 构建build:name: 构建应用runs-on: ubuntu-latestneeds: qualitysteps:- name: Checkoutuses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Buildrun: npm run build- name: Upload build artifactsuses: actions/upload-artifact@v3with:name: build-filespath: build/retention-days: 7# 部署deploy:name: 部署到 Vercelruns-on: ubuntu-latestneeds: buildif: github.ref == 'refs/heads/main'steps:- name: Checkoutuses: actions/checkout@v4- name: Deploy to Verceluses: amondnet/vercel-action@v25with: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 项目
name: Node.js API CI/CDon:push:branches: [ main, develop ]pull_request:branches: [ main ]env:NODE_VERSION: '18'REGISTRY: ghcr.ioIMAGE_NAME: ${{ github.repository }}jobs:# 测试test:name: 测试runs-on: ubuntu-latestservices:postgres:image: postgres:15env:POSTGRES_PASSWORD: postgresPOSTGRES_DB: test_dboptions: >---health-cmd pg_isready--health-interval 10s--health-timeout 5s--health-retries 5ports:- 5432:5432steps:- name: Checkoutuses: actions/checkout@v4- name: Setup Node.jsuses: actions/setup-node@v4with:node-version: ${{ env.NODE_VERSION }}cache: 'npm'- name: Install dependenciesrun: npm ci- name: Run migrationsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_dbrun: npm run db:migrate- name: Run testsenv:DATABASE_URL: postgresql://postgres:postgres@localhost:5432/test_dbrun: npm run test:coverage- name: Upload coverageuses: codecov/codecov-action@v3# 构建 Docker 镜像build:name: 构建镜像runs-on: ubuntu-latestneeds: teststeps:- name: Checkoutuses: actions/checkout@v4- name: Setup Docker Buildxuses: docker/setup-buildx-action@v3- name: Login to registryuses: docker/login-action@v3with:registry: ${{ env.REGISTRY }}username: ${{ github.actor }}password: ${{ secrets.GITHUB_TOKEN }}- name: Extract metadataid: metauses: docker/metadata-action@v5with:images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}tags: |type=ref,event=branchtype=ref,event=prtype=sha- name: Build and pushuses: docker/build-push-action@v5with:context: .push: truetags: ${{ steps.meta.outputs.tags }}labels: ${{ steps.meta.outputs.labels }}cache-from: type=ghacache-to: type=gha,mode=max# 部署deploy:name: 部署runs-on: ubuntu-latestneeds: buildif: github.ref == 'refs/heads/main'environment: productionsteps:- name: Deploy to serveruses: appleboy/ssh-action@v1.0.0with:host: ${{ secrets.HOST }}username: ${{ secrets.USERNAME }}key: ${{ secrets.SSH_KEY }}script: |docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:maindocker stop api || truedocker rm api || truedocker 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 的核心概念、实践案例和最佳实践。通过学习和应用这些知识,您将能够构建高效、安全、可靠的自动化部署流程。
