自托管 GitHub Runner

集群用 Actions Runner Controller(ARC v2,gha-runner-scale-set)跑自托管 runner。一个共享 controller 部署在 arc-systems namespace,管理 github-runner / kamify-runner / everyapi-runner 三套 AutoscalingRunnerSet,分别服务三个 GitHub 组织。工作流用 runs-on: yldm-backend-runners 把任务投到对应的 scale set。

三套 Scale Set

三套 AutoscalingRunnerSet 共享相同的 ARC/DinD 结构,差别包括 namespace、scale-set 名字、绑定的 GitHub 组织、伸缩范围和 runner 镜像:

  • Name
    github-runner / yldm-backend-runners
    Description
    namespace github-runner,绑定组织 yldm-techgithubConfigUrl: https://github.com/yldm-tech)。minRunners: 2,常驻两个 runner。
  • Name
    kamify-runner / kamify-backend-runners
    Description
    namespace kamify-runner,绑定组织 kamify-aiminRunners: 0,空闲时不留 runner,按需拉起。
  • Name
    everyapi-runner / everyapi-backend-runners
    Description
    namespace everyapi-runner,绑定组织 everyapi-aiminRunners: 0,同样按需伸缩。

三套都用 apiVersion: actions.github.com/v1alpha1kind: AutoscalingRunnerSetactiveDeadlineSeconds: 7200(防僵尸 runner,2 小时强制终止)。当前安全上限为 yldm maxRunners: 6、kamify/everyapi maxRunners: 4,受 worker1 + worker3 共享 CI 池的实际内存约束。

共享 Controller

arc-v2-controller.yamlarc-systems 里部署单副本的 gha-runner-scale-set-controller Deployment(镜像 ghcr.io/actions/gha-runner-scale-set-controller:0.14.2),同时定义它的 ServiceAccount、ClusterRole/ClusterRoleBinding(管理 actions.github.com 下的 autoscalinglisteners、autoscalingrunnersets、ephemeralrunners、ephemeralrunnersets 等)以及 leader-election 的 Role/RoleBinding。

controller 启动参数 --auto-scaling-runner-set-only --update-strategy=eventualnodeSelector: node-role=cicd,跑在只读根文件系统、非 root 的 securityContext 下,8080 端口暴露 metrics。它为每个 scale set 维护一个 listener,由 listener 监听 GitHub 的任务队列并按需创建 EphemeralRunner。

Runner Pod 结构

每个 runner Pod 跑两个容器,共享一对 emptyDirdocker-certs 放 TLS 证书、dind-storage 放 Docker 数据):

容器镜像角色requestslimits
runnerghcr.io/yldm-tech/actions-runner-with-gh:latest(yldm/kamify)或 actions-runner-everyapi:latest(EveryAPI)/home/runner/run.sh;EveryAPI 镜像额外预装 Tauri/WebKitGTK 开发库250m / 1Gi2 / 4Gi
dinddocker:dindprivileged Docker-in-Docker sidecar,供 docker build/push100m / 512Mi2 / 2Gi

runner 容器通过 DOCKER_HOST=tcp://localhost:2376 + TLS(DOCKER_TLS_VERIFY=1,证书在 /certs/client)连到 dind sidecar。共享镜像 actions-runner-with-gh 构建自 applications/infrastructure/github-runner/Dockerfile;EveryAPI 的 actions-runner-everyapi 再从共享镜像派生,构建源在 applications/infrastructure/everyapi-runner/Dockerfilebuild-runner-image.yml 按顺序构建并推送两者,保证派生镜像总是使用刚发布的共享基础镜像。

认证与镜像拉取

ARC 走一个由 yldm-tech 持有的共享 GitHub App 认证,不是 PAT。每套 runner 的 github-token ExternalSecret 从 Vault 经 ClusterSecretStore vault-backend 读三个 key 组装出 App 凭证:app_idinstallation_idprivate_key。各 namespace 的 Vault 路径不同(如 github-runner/github-appkamify-runner/github-app),各组织用各自的 Installation ID。ARC 检测到这三个 key 就会用 App 凭证而非 github_token 去认证。

另有一个独立的 PAT 用于 GHCR 拉镜像(不是死代码):ghcr-pull-secret ExternalSecret 从 Vault github-runner/github-tokentoken,模板化成 kubernetes.io/dockerconfigjson 类型的 ghcr.io 凭证,runner Pod 的 imagePullSecrets 引用它来拉私有 runner 镜像。

伸缩与配额

listener 监听到 GitHub 的排队任务时才创建 EphemeralRunner,任务跑完即销毁。minRunners: 0 的 scale set 空闲挂在 0 个 runner 是正常状态,并非故障;缩容期间偶发的 secret "...-runner-xxx" not found 是 jitconfig secret 随 EphemeralRunner 一起删除的良性 teardown 竞争,只有 failedEphemeralRunners > 0 才需要关注。

github-runner namespace 设了 ResourceQuota:pods: 25requests.cpu: 10requests.memory: 24Gilimits.cpu: 96limits.memory: 96Gi。三套 scale set 的上限按共享节点池而不是单 namespace 配额计算;当前 6 + 4 + 4 的上限刻意为 churn 时终止中的 Pod 重叠留余量。Pod 创建被配额或节点容量拒绝会让 ARC 的 EphemeralRunner 永久失败、卡死整个 scale set(2026-06-12 的教训)。

升级 Controller 版本

controller 会在每次 reconcile 时删除 app.kubernetes.io/version label 不等于 自身构建版本的 AutoscalingRunnerSet。版本 bump 漏改任何一处就会让 runner set 陷入删除/重建循环 → 没有 listener → 0 个 runner(曾导致数周的 P0)。改 gha-runner-scale-set-controller:<ver> 时必须四处同步到同一个 <ver>

#文件字段
arc-v2-controller.yamlcontroller 的 image
arc-v2-controller.yamlCONTROLLER_MANAGER_CONTAINER_IMAGE env
③④⑤三个 runner 目录的 autoscaling-runner-set.yamlapp.kubernetes.io/version label

CONTROLLER_MANAGER_CONTAINER_IMAGE 是 controller 拿来拉起 listener Pod 的镜像;它若落后,listener 会跑旧二进制并以 GitHubConfigUrl is not provided 崩溃(旧 listener 解析不了新格式的配置)。当前所有引用都在 0.14.2

# 一次性找出全部四处引用
grep -rn "gha-runner-scale-set-controller:\|app.kubernetes.io/version" \
  applications/infrastructure/*runner*/

评论