Github Actions:从发现任务批量启动多仓库容器更新任务的问题
解决方案:GitHub Actions 动态容器更新任务实现
原配置的核心问题是矩阵化的 discover-job 输出会被覆盖:GitHub Actions 中,矩阵任务的全局输出只会保留最后一个完成的矩阵实例结果,导致你只能拿到最后一个仓库的更新数据。以下是两种可行的实现方案:
方案一:单任务批量发现(适合中小规模仓库)
放弃矩阵化的 discover-job,在单个任务中遍历所有仓库,一次性收集所有需要更新的 <仓库,标签> 对,输出为 JSON 数组后供 update-job 做矩阵遍历。
配置示例
on: workflow_dispatch: schedule: - cron: "0 0 * * *" jobs: discover-job: name: 批量发现需更新的容器镜像 runs-on: ubuntu-latest outputs: update_list: ${{ steps.collect-updates.outputs.update_list }} steps: - name: 遍历仓库收集更新任务 id: collect-updates run: | # 初始化空的更新任务数组 UPDATE_LIST='[]' # 遍历所有目标仓库 for REPO in repo1 repo2 repo3; do # 替换为你的标签发现逻辑,返回空格分隔的需更新标签列表 TAGS=$(your-discover-script.sh "$REPO") # 将每个标签转为<仓库,标签>对,加入数组 for TAG in $TAGS; do UPDATE_LIST=$(echo "$UPDATE_LIST" | jq --arg repo "$REPO" --arg tag "$TAG" '. += [{"repo": $repo, "tag": $tag}]') done done # 输出JSON格式的任务列表 echo "update_list=$UPDATE_LIST" >> "$GITHUB_OUTPUT" update-job: name: 更新容器 ${{ matrix.item.repo }}:${{ matrix.item.tag }} needs: discover-job runs-on: ubuntu-latest strategy: matrix: item: ${{ fromJSON(needs.discover-job.outputs.update_list) }} steps: - name: 执行容器更新 run: | # 替换为你的容器更新逻辑 echo "开始更新 ${MATRIX_REPO}:${MATRIX_TAG}" # your-update-script.sh "$MATRIX_REPO" "$MATRIX_TAG" env: MATRIX_REPO: ${{ matrix.item.repo }} MATRIX_TAG: ${{ matrix.item.tag }}
方案二:矩阵发现+结果汇总(适合大规模仓库)
保留矩阵化的 discover-job 并行处理每个仓库,将每个仓库的更新结果保存为独立文件上传到 artifacts,再通过一个汇总任务合并所有结果,生成统一的任务数组供 update-job 使用。
配置示例
on: workflow_dispatch: schedule: - cron: "0 0 * * *" jobs: discover-job: name: 发现仓库 ${{ matrix.repo }} 的更新标签 runs-on: ubuntu-latest strategy: matrix: repo: [repo1, repo2, repo3] steps: - name: 识别需更新的标签 id: find-tags run: | # 替换为你的标签发现逻辑,返回空格分隔的需更新标签列表 TAGS=$(your-discover-script.sh "${{ matrix.repo }}") # 将标签转为JSON数组,保存为独立文件 TAG_JSON=$(echo "$TAGS" | tr ' ' '\n' | jq -R . | jq -s .) echo "{\"repo\": \"${{ matrix.repo }}\", \"tags\": $TAG_JSON}" > "updates-${{ matrix.repo }}.json" - name: 上传仓库更新结果 uses: actions/upload-artifact@v4 with: name: updates-${{ matrix.repo }} path: updates-${{ matrix.repo }}.json if-no-files-found: ignore # 无更新时跳过上传 aggregate-updates: name: 汇总所有更新任务 runs-on: ubuntu-latest needs: discover-job outputs: update_list: ${{ steps.aggregate.outputs.update_list }} steps: - name: 下载所有仓库的更新结果文件 uses: actions/download-artifact@v4 with: path: ./artifacts - name: 合并为统一的更新任务数组 id: aggregate run: | UPDATE_LIST='[]' # 遍历所有下载的结果文件 for FILE in ./artifacts/**/*.json; do if [ -f "$FILE" ]; then REPO=$(jq -r '.repo' "$FILE") TAGS=$(jq -r '.tags[]' "$FILE") # 将每个标签转为<仓库,标签>对,加入数组 for TAG in $TAGS; do UPDATE_LIST=$(echo "$UPDATE_LIST" | jq --arg repo "$REPO" --arg tag "$TAG" '. += [{"repo": $repo, "tag": $tag}]') done fi done echo "update_list=$UPDATE_LIST" >> "$GITHUB_OUTPUT" update-job: name: 更新容器 ${{ matrix.item.repo }}:${{ matrix.item.tag }} needs: aggregate-updates runs-on: ubuntu-latest strategy: matrix: item: ${{ fromJSON(needs.aggregate-updates.outputs.update_list) }} steps: - name: 执行容器更新 run: | # 替换为你的容器更新逻辑 echo "开始更新 ${MATRIX_REPO}:${MATRIX_TAG}" # your-update-script.sh "$MATRIX_REPO" "$MATRIX_TAG" env: MATRIX_REPO: ${{ matrix.item.repo }} MATRIX_TAG: ${{ matrix.item.tag }}
注意事项
- 依赖工具:确保 runner 环境安装了
jq(ubuntu-latest默认自带,其他系统需手动安装),用于处理 JSON 数据。 - 空任务处理:如果没有任何需要更新的标签,
update-job的矩阵会为空,任务会直接跳过。可在汇总步骤中添加判断,输出空数组时跳过update-job。 - 大规模场景优化:对于 100+ 仓库的场景,方案二的并行发现能大幅节省时间,矩阵任务默认最多并行 25 个实例,可通过
max-parallel参数调整。
内容的提问来源于stack exchange,提问作者Dave B
相关产品推荐
相关产品推荐

