在上一篇中,我们学会了如何用 Workflow 定义基础的 CI 流水线。当项目需要支持多版本运行时(如 Node.js 14/16/18)、多操作系统(Linux/Windows/macOS),或者需要部署到 dev/staging/prod 多个环境时,简单的顺序执行已经不够用了。本文深入讲解 GitHub Actions 的三大进阶能力:矩阵构建(Matrix Strategy) 实现并行测试、依赖缓存(Caching) 加速构建、以及多环境部署(Environments) 实现环境隔离与安全审批。掌握这些技术,你的流水线将从“能用”走向“高效、安全、可扩展”。

一、矩阵构建(Matrix Strategy):一次定义,并行执行
矩阵策略允许你定义一组变量,GitHub Actions 会为这些变量的每一种组合创建一个独立的 Job 并并行执行。它特别适合:

多语言版本测试(如 Python 3.8/3.9/3.10)

多操作系统兼容性测试(如 ubuntu/windows/macos)

多浏览器或多数据库版本的集成测试

1.1 基础矩阵配置
以下示例展示了如何针对三个 Node.js 版本在两个操作系统上运行测试,共生成 3 × 2 = 6 个并行 Job:

name: Matrix Test

on: [push, pull_request]

jobs:
  test:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        node-version: [18, 20, 22]
        os: [ubuntu-latest, windows-latest]
    steps:
      - uses: actions/checkout@v4
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
      - run: npm ci
      - run: npm test

矩阵中的每个组合都是独立的 Job,互不影响。如果某个组合失败,其他组合仍会继续执行(除非设置了 fail-fast: false)。

1.2 高级矩阵控制
排除特定组合:当某些组合没有意义时(如 Windows 上不需要测试某个旧版本),可以使用 exclude 排除:

strategy:
  matrix:
    node-version: [18, 20, 22]
    os: [ubuntu-latest, windows-latest]
  exclude:
    - os: windows-latest
      node-version: 18   # 不在 Windows 上测试 Node 18

包含额外组合:使用 include 添加不在矩阵组合中的额外 Job:

strategy:
  matrix:
    node-version: [18, 20]
    os: [ubuntu-latest]
  include:
    - os: windows-latest
      node-version: 22   # 额外在 Windows 上测试 Node 22

控制失败传播:设置 fail-fast: false 可以让所有矩阵 Job 都运行完毕,即使其中某些失败:

strategy:
  fail-fast: false
  matrix:
    node-version: [18, 20, 22]

1.3 将矩阵输出用于后续 Job
矩阵 Job 产生的构建产物(如测试报告、JAR 包)可以通过 upload-artifact 保存,后续 Job 通过 download-artifact 汇总:

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node-version: [18, 20, 22]
    steps:
      - run: npm test -- --coverage
      - name: Upload coverage report
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report-node-${{ matrix.node-version }}
          path: coverage/

  merge-reports:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - name: Download all coverage reports
        uses: actions/download-artifact@v4
        with:
          path: all-reports/
      - run: ./merge-coverage.sh all-reports/

二、依赖缓存(Caching):让构建快如闪电
每次 Workflow 运行时,如果都要重新下载所有依赖(如 Maven 的 .m2、npm 的 node_modules),不仅耗时而且浪费带宽。缓存(Caching) 允许你将依赖目录保存下来,在后续的 Workflow 运行中复用。

2.1 使用语言内置缓存(最简方式)
大多数官方 setup-* Action 都内置了缓存支持,这是最简单的方式:

- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'   # 自动缓存 ~/.npm
yaml
- uses: actions/setup-java@v4
  with:
    distribution: 'temurin'
    java-version: '17'
    cache: 'maven'   # 自动缓存 ~/.m2/repository

2.2 使用 actions/cache 手动控制
当需要更精细的缓存控制时,可以使用 actions/cache:

- name: Cache Maven dependencies
  uses: actions/cache@v4
  with:
    path: ~/.m2/repository
    key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
    restore-keys: |
      ${{ runner.os }}-m2-

key:缓存的唯一标识。当 pom.xml 变化时,hashFiles 会生成新的哈希值,自动创建新的缓存。

restore-keys:如果精确的 key 未命中,按顺序尝试恢复部分匹配的缓存。

💡 最佳实践:对于 Maven 项目,建议先执行 mvn dependency:go-offline 下载依赖,再执行 mvn package,这样缓存能覆盖所有依赖。

2.3 缓存的限制与注意事项
GitHub 的缓存总大小限制为 10GB(每个仓库)。

缓存的有效期为 7 天(未被访问的缓存会被自动清理)。

缓存 Key 的设计要合理:太粗(如只用 runner.os)会导致缓存频繁被覆盖;太细(如包含所有源码的哈希)会导致缓存几乎无法命中。

三、多环境部署(Environments):环境隔离与安全审批
GitHub Environments 是一个强大的部署管理功能,它允许你为不同的部署目标(如 dev、staging、prod)配置独立的环境变量、密钥(Secrets) 和保护规则(Protection Rules) 。当一个 Job 引用某个环境时,它必须通过该环境的所有保护规则才能执行或访问环境密钥。

3.1 创建环境
在 GitHub 仓库中:

进入 Settings → Environments

点击 New environment,输入名称(如 production)

配置保护规则:

Required reviewers:指定需要审批的人员或团队(最多 6 人)

Wait timer:部署前等待指定时间(如 5 分钟)

Branch restrictions:限制只有特定分支才能部署到该环境

3.2 在 Workflow 中使用环境

name: Multi-Environment Deployment

on:
  push:
    branches: [main, develop]

jobs:
  deploy-dev:
    runs-on: ubuntu-latest
    environment: dev   # 引用 dev 环境
    steps:
      - run: echo "部署到开发环境"
      - run: echo "DB_HOST: ${{ secrets.DB_HOST }}"   # 使用环境密钥

  deploy-staging:
    runs-on: ubuntu-latest
    environment: staging
    if: github.ref == 'refs/heads/develop'   # 仅 develop 分支触发
    steps:
      - run: echo "部署到预发布环境"

  deploy-prod:
    runs-on: ubuntu-latest
    environment: production   # 引用 production 环境
    if: github.ref == 'refs/heads/main'
    steps:
      - run: echo "部署到生产环境"

3.3 环境审批(Required Reviewers)的工作流程
当 Job 引用了一个配置了 Required reviewers 的环境时:

Job 启动后会自动暂停,状态变为 Waiting for approval。

被指定为审批人的用户或团队成员会收到通知。

审批人点击 Review deployments 并批准后,Job 才会继续执行。

如果被拒绝,Job 失败并停止。

3.4 环境级别的密钥与变量
每个环境可以独立配置 Secrets 和 Variables:

环境	DB_HOST	API_KEY	说明
dev	db.dev.example.com	dev-key-xxx	开发环境配置
staging	db.staging.example.com	staging-key-xxx	预发布环境配置
production	db.prod.example.com	prod-key-xxx	生产环境配置(需审批)

在 Workflow 中,环境密钥的引用方式与普通 Secrets 相同:${{ secrets.API_KEY }}。Job 引用的环境决定了使用哪一组密钥。

四、完整实战:矩阵构建 + 缓存 + 多环境部署
下面是一个综合示例,展示了如何将矩阵构建、依赖缓存和多环境部署整合到一条完整的 CI/CD 流水线中:

name: CI/CD Pipeline

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

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

jobs:
  # ===== Job 1: 矩阵测试 =====
  test:
    name: Test on ${{ matrix.os }} / Node ${{ matrix.node-version }}
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        node-version: [18, 20]
        os: [ubuntu-latest, windows-latest]
      fail-fast: false
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node-version }}
          cache: 'npm'
      - run: npm ci
      - run: npm test
      - name: Upload test report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: test-report-${{ matrix.os }}-${{ matrix.node-version }}
          path: test-results/

  # ===== Job 2: 构建镜像(仅 main 分支) =====
  build:
    runs-on: ubuntu-latest
    needs: test
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      - name: Cache Maven dependencies
        uses: actions/cache@v4
        with:
          path: ~/.m2/repository
          key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
          restore-keys: ${{ runner.os }}-m2-
      - name: Build with Maven
        run: mvn package
      - name: Build Docker image
        run: docker build -t ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} .

  # ===== Job 3: 部署到开发环境(develop 分支自动) =====
  deploy-dev:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/develop'
    environment:
      name: dev
      url: https://dev.myapp.example.com
    steps:
      - run: echo "部署到开发环境"
      - run: echo "DB: ${{ secrets.DB_HOST }}"

  # ===== Job 4: 部署到生产环境(main 分支需审批) =====
  deploy-prod:
    runs-on: ubuntu-latest
    needs: build
    if: github.ref == 'refs/heads/main'
    environment:
      name: production
      url: https://myapp.example.com
    steps:
      - run: echo "部署到生产环境(需审批)"
      - run: echo "DB: ${{ secrets.DB_HOST }}"

五、小结
矩阵构建:通过 strategy.matrix 一次定义、并行执行多版本/多平台测试

依赖缓存:使用 actions/cache 或语言内置缓存,大幅减少构建时间

多环境部署:通过 environment 关键字实现环境隔离,配合 Required reviewers 实现审批门禁

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐