GitHub Actions默认runner不可用时,如何自动切换至自托管runner?
解决GitHub Actions自动切换自托管Runner的方案
我们平时用GitHub Actions默认的ubuntu-latest runner,但遇到付费限制时需要切换到自托管实例。你当前靠仓库topics判断runner的方案存在两个问题:无法自动检测runner状态、重跑作业时上下文里的topics不会更新。下面给几个可行的解决办法:
方案一:自动检测自托管Runner状态(完全自动化)
通过前置作业实时查询仓库里的自托管runner是否在线,动态决定后续作业使用的runner。重跑时这个检测会重新执行,完美解决上下文不更新的问题。
jobs: check-runner-status: runs-on: ubuntu-latest # 这个轻量检测用默认runner即可,消耗极小 outputs: target-runner: ${{ steps.detect.outputs.runner }} steps: - name: 检测在线自托管Runner id: detect run: | # 查询仓库所有runner,过滤出状态为online且带self-hosted标签的 HAS_ONLINE_SELF_HOSTED=$(gh api repos/${{ github.repository }}/runners --jq '.runners[] | select(.status == "online") | .labels[].name' | grep -q "self-hosted" && echo "true" || echo "false") if [ "$HAS_ONLINE_SELF_HOSTED" = "true" ]; then echo "runner=self-hosted" >> $GITHUB_OUTPUT else echo "runner=ubuntu-latest" >> $GITHUB_OUTPUT fi env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} main-job: name: 核心作业 needs: check-runner-status runs-on: ${{ needs.check-runner-status.outputs.target-runner }} steps: - name: 执行作业内容 run: echo "当前运行在: ${{ runner.name }}"
注意事项
- 默认的
GITHUB_TOKEN已经具备读取仓库runner状态的权限,不需要额外配置 - 如果你的自托管runner用了自定义标签(比如
self-hosted-linux),把grep的内容改成对应的标签名称即可
方案二:手动指定Runner(灵活干预)
通过工作流的手动触发选项,允许你直接选择要使用的runner,重跑作业时也能重新选择,彻底绕开上下文缓存的问题。
name: 可选择Runner的工作流 on: push: # 代码推送时默认用ubuntu-latest workflow_dispatch: # 手动触发时可选择runner inputs: runner-type: description: 选择运行的Runner required: true default: 'ubuntu-latest' type: choice options: - ubuntu-latest - self-hosted jobs: main-job: name: 核心作业 runs-on: ${{ github.event.inputs.runner-type || 'ubuntu-latest' }} steps: - name: 执行作业内容 run: echo "当前运行在: ${{ runner.name }}"
使用方式
- 日常推送代码自动用默认runner
- 需要切换自托管时,在GitHub仓库的Actions页面手动触发该工作流,选择
self-hosted - 重跑失败作业时,在重跑界面可以重新选择runner类型
方案三:修复原Topics方案的重跑问题
如果你想保留用仓库topics控制的逻辑,可以通过前置作业实时拉取最新的topics,而不是依赖触发时的github.event缓存数据。
jobs: fetch-latest-topics: runs-on: ubuntu-latest outputs: use-self-hosted: ${{ steps.check.outputs.result }} steps: - name: 获取最新仓库Topics id: check run: | # 查询仓库当前的topics列表,判断是否包含self-hosted TOPICS_CONTAINS=$(gh api repos/${{ github.repository }} --jq '.topics | contains(["self-hosted"])') echo "result=$TOPICS_CONTAINS" >> $GITHUB_OUTPUT env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} main-job: name: 核心作业 needs: fetch-latest-topics runs-on: ${{ needs.fetch-latest-topics.outputs.use-self-hosted == 'true' && 'self-hosted' || 'ubuntu-latest' }} steps: - name: 执行作业内容 run: echo "当前运行在: ${{ runner.name }}"
这个方案重跑时会重新拉取最新的topics状态,解决了原方案重跑时上下文不更新的问题。
内容的提问来源于stack exchange,提问作者rzlvmp
相关产品推荐
相关产品推荐

