GitHub Actions不使用独立Job时如何借助Matrix实现同代理顺序循环
实现方法
原生GitHub Actions的Matrix默认会为每个参数组合生成独立并行job,且默认分配独立临时执行实例,要满足同一build agent、顺序执行、跨迭代读取历史输出的需求,可通过两类配置实现:
方案1:保留原生Matrix结构,调整配置满足约束
关键配置调整
- 关闭并行执行:在Matrix策略中设置
max-parallel: 1,强制一次仅运行一个矩阵组合,从调度层面杜绝并行 - 锁定固定执行agent:必须使用带固定标识的自托管runner,不可使用GitHub托管的临时runner——后者会为每个独立job分配全新的销毁式VM,无法保证所有迭代运行在同一台物理/虚拟agent上。配置时通过
runs-on标签指定唯一的固定runner实例即可 - 解决跨job上下文隔离问题:由于每个矩阵组合本质是独立job,默认不共享环境变量、步骤输出,因此需要通过runner本地的持久路径存储跨迭代状态:
- 所有文件类输出直接存入runner上不受checkout流程影响的固定路径(比如
/tmp/gh-matrix-loop),后续迭代可直接通过路径读取,无需走artifact上传下载流程 - 需要跨迭代传递的步骤变量(比如计算结果、计数器、配置值),直接写入固定路径下的环境变量文件(比如
state.env),每个迭代开头先加载该文件的内容,即可获取所有历史迭代写入的值
- 所有文件类输出直接存入runner上不受checkout流程影响的固定路径(比如
- 可选配置:设置
fail-fast: false,避免单个迭代失败时提前终止后续的顺序执行流程
最小配置示例
jobs: sequential-matrix-run: runs-on: [self-hosted, linux, fixed-runner-01] strategy: fail-fast: false max-parallel: 1 matrix: # 自定义需要组合的参数 env: [dev, staging, prod] build_mode: [debug, release] steps: - name: 加载历史迭代状态 run: | mkdir -p /tmp/gh-matrix-loop # 存在状态文件就加载,不存在就初始化 if [ -f /tmp/gh-matrix-loop/state.env ]; then source /tmp/gh-matrix-loop/state.env else echo "ITER_COUNTER=0" > /tmp/gh-matrix-loop/state.env fi - name: 执行当前迭代逻辑 run: | echo "正在执行第 ${ITER_COUNTER} 次迭代,参数:${{ matrix.env }} / ${{ matrix.build_mode }}" # 执行你的构建、测试逻辑,输出直接存在本地可被后续迭代读取 # 把当前迭代的状态写入文件供下一次使用 echo "LAST_RUN_PARAM=${{ matrix.env }}-${{ matrix.build_mode }}" >> /tmp/gh-matrix-loop/state.env echo "ITER_COUNTER=$((ITER_COUNTER + 1))" >> /tmp/gh-matrix-loop/state.env
方案2:复用Matrix的组合生成能力,单job内实现顺序循环
如果不需要每个矩阵组合拥有独立的job级能力(比如独立失败重试、独立状态追踪),可以绕过原生Matrix的多job生成逻辑,减少跨上下文传递的开销:
- 新增前置预处理job,使用原生Matrix的参数组合能力,生成所有需要循环的参数序列,输出为结构化JSON数组
- 将生成的参数数组通过job级输出,传递给下游的单一执行job
- 下游job绑定固定runner,在单个步骤内用shell语法遍历参数数组,写普通的for循环逐次执行逻辑,全程所有步骤都在同一个agent、同一个job上下文内,天然不并行、天然能读取之前步骤的所有输出和文件
注意避坑
- 不可使用GitHub托管runner实现「同一build agent」的核心要求:托管runner是临时销毁式实例,即使设置
max-parallel:1,也会为每个job分配全新的VM,无法保留之前迭代的文件和输出 - 跨迭代的状态文件必须存在与代码仓库路径完全无关的系统级路径下(比如
/tmp目录),不可存在仓库默认工作目录中——否则每个job的checkout流程会重置工作目录内容,丢失历史状态 - 若硬要使用托管runner模拟跨迭代传值,需要每次迭代结束把文件上传为artifact,下一次迭代开头再下载,整个流程不是运行在同一agent上,且传输开销极高,不符合原始需求
内容的提问来源于stack exchange,提问作者Mathias Lykkegaard Lorenzen
相关产品推荐
相关产品推荐

