GitHub Actions Runner Controller (ARC) 部署与问题排查指南
记录从零开始在 Kubernetes 上部署 ARC 0.12.1 遇到的问题及解决方案
背景
在 Kubernetes 集群上部署 GitHub Actions Runner Controller (ARC),用于在自托管的 Kubernetes 环境中运行 GitHub Actions workflows,支持 Docker 镜像构建。
环境信息:
- Kubernetes 版本:v1.32.5
- ARC 版本:0.12.1
- GitHub 组织:免费计划
- 认证方式:Personal Access Token (PAT)
部署过程
1. 安装 ARC Controller
1
2
3
4
|
helm install arc \\
--namespace action \\
--create-namespace \\
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
|
2. 创建 GitHub PAT Secret
1
2
3
|
kubectl create secret generic github-pat-secret \\
--namespace=action \\
--from-literal=github_token='your-pat-token'
|
PAT 所需权限:
- Actions: Read and write
- Administration: Read and write
核心问题:minRunners 配置导致 Ephemeral Runners 无法工作
问题现象
使用以下配置时,workflows 一直卡在 “Waiting for a runner to pick up this job…” 状态:
1
2
3
4
5
6
|
# ❌ 错误配置
githubConfigUrl: "<https://github.com/your-org>"
githubConfigSecret: github-pat-secret
runnerScaleSetName: "your-runners"
minRunners: 1 # 这是问题所在!
maxRunners: 5
|
观察到的症状:
-
Runner pods 快速启动后在 1-3 秒内完成并删除
-
Pod 状态:Pending → ContainerCreating → Running → Completed → Terminating
-
Listener 日志显示:
1
2
3
4
5
|
{
"totalAssignedJobs": 2,
"totalRegisteredRunners": 2,
"totalIdleRunners": 0
}
|
-
GitHub API 显示 runners 已注册但状态为 “offline”,且 labels 为空 []
-
Workflows 永远停留在队列中
问题根因分析
ARC 0.12.x 使用的是 Ephemeral Runners(临时运行器)架构,基于 JIT (Just-In-Time) 配置:
- 每个 ephemeral runner 在创建时必须绑定到特定的 job
- Runner 通过 JIT configuration token 获取其应该执行的 job 信息
- Runner 生命周期:启动 → 注册 → 执行 job → 上传结果 → 注销 → 退出
当设置 minRunners: 1 时:
- ARC 为了满足最小数量要求,创建 1 个"待命" runner
- 这个 runner 没有绑定任何 job(因为它不是为特定 job 创建的)
- Runner 启动后发现 JIT token 中没有 job 信息,认为任务已完成
- Runner 立即标记为 “Succeeded” 并退出
- 当真正的 workflow job 到来时:
- GitHub 尝试将 job 分配给这个 runner scale set
- 但所有 runners 都已经 offline(已完成并删除)
- Job 无法被分配,永远停留在队列中
解决方案
将 minRunners 设置为 0****:
1
2
3
4
5
6
|
# ✅ 正确配置
githubConfigUrl: "<https://github.com/your-org>"
githubConfigSecret: github-pat-secret
runnerScaleSetName: "your-runners"
minRunners: 0 # 关键配置!
maxRunners: 5
|
正确的工作流程:
- Workflow job 进入队列
- GitHub 通知 ARC listener:“有 job 分配给这个 runner scale set”
- Listener 触发 ARC controller 创建新的 ephemeral runner
- 新创建的 runner 的 JIT token 已经绑定了这个 job
- Runner 启动 → 执行 job → 完成 → 退出
- 整个过程流畅,job 通常在 15-20 秒内完成
验证解决方案
应用正确配置:
1
2
3
4
|
helm upgrade shiliuzi-runners \\
--namespace action \\
-f arc-values-minimal.yaml \\
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
|
触发测试 workflow:
1
2
3
4
5
6
7
8
9
|
name: Test ARC Runner
on: workflow_dispatch
jobs:
test:
runs-on: your-runners # 使用 runner scale set 名称
steps:
- name: Test
run: echo "SUCCESS!"
|
结果:✅ 成功执行,15 秒完成
问题 2:启用 Docker-in-Docker (DinD) 支持
需求
需要在 runners 中构建 Docker 镜像,这需要 Docker daemon。
配置 DinD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
githubConfigUrl: "<https://github.com/your-org>"
githubConfigSecret: github-pat-secret
runnerScaleSetName: "your-runners"
minRunners: 0
maxRunners: 5
containerMode:
type: "dind" # 启用 Docker-in-Docker
template:
spec:
containers:
- name: runner
image: ghcr.io/actions/actions-runner:latest
command: ["/home/runner/run.sh"]
env:
- name: DOCKER_HOST
value: unix:///var/run/docker.sock
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "2"
memory: "4Gi"
volumeMounts:
- name: work
mountPath: /home/runner/_work
- name: dind
image: docker:dind
securityContext:
privileged: true
volumeMounts:
- name: work
mountPath: /home/runner/_work
- name: dind-storage
mountPath: /var/lib/docker
volumes:
- name: work
emptyDir: {}
- name: dind-storage
emptyDir: {}
|
DinD 架构说明
每个 runner pod 包含 2 个容器:
- runner 容器:执行 GitHub Actions workflows
- dind 容器:运行 Docker daemon(privileged 模式)
两个容器通过共享的 Unix socket (/var/run/docker.sock) 通信。
验证 Docker 功能
测试 workflow:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
name: Test Docker Build
on: workflow_dispatch
jobs:
test-docker:
runs-on: your-runners
steps:
- name: Check Docker
run: docker --version
- name: Build Image
run: |
cat > Dockerfile <<EOF
FROM alpine:latest
RUN echo "Hello from Docker!"
EOF
docker build -t test:latest .
- name: Run Container
run: docker run --rm test:latest echo "Success!"
|
结果:✅ 成功构建和运行容器
输出示例:
1
2
3
|
Docker version 28.5.1, build e180ab8
Successfully built image
Success!
|
其他发现与注意事项
1. Runner Labels 为空
通过 GitHub API 查询时,ephemeral runners 的 labels 字段为空 []:
1
2
|
gh api /orgs/your-org/actions/runners
# 输出:"labels": []
|
这是正常的! 这是 ARC 0.12.x 的设计行为(参见 GitHub Issue #3330)。
Workflows 应该使用 runner scale set 名称来匹配:
1
2
3
4
5
|
# ✅ 正确
runs-on: your-runners
# ❌ 错误(在 ARC 0.12.x 中不工作)
runs-on: self-hosted
|
2. Runner Group 配置
确保 runner group 允许你的仓库访问:
1
2
3
4
5
6
7
8
9
|
# 检查 runner group
gh api /orgs/your-org/actions/runner-groups/1
# 输出应包含:
{
"name": "Default",
"visibility": "all",
"allows_public_repositories": false # private 仓库可以访问
}
|
3. 版本兼容性
- ARC 0.9.3 不兼容 Kubernetes 1.32.5(API validation errors)
- ARC 0.12.1 与 Kubernetes 1.32.5 完全兼容
- 建议使用最新的 ARC 版本
最终配置文件
基础配置(无 Docker)
1
2
3
4
5
6
|
# arc-values-minimal.yaml
githubConfigUrl: "<https://github.com/your-org>"
githubConfigSecret: github-pat-secret
runnerScaleSetName: "your-runners"
minRunners: 0
maxRunners: 5
|
完整配置(带 DinD)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
# arc-values-with-dind.yaml
githubConfigUrl: "<https://github.com/your-org>"
githubConfigSecret: github-pat-secret
runnerScaleSetName: "your-runners"
minRunners: 0
maxRunners: 5
containerMode:
type: "dind"
template:
spec:
containers:
- name: runner
image: ghcr.io/actions/actions-runner:latest
command: ["/home/runner/run.sh"]
env:
- name: DOCKER_HOST
value: unix:///var/run/docker.sock
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "2"
memory: "4Gi"
volumeMounts:
- name: work
mountPath: /home/runner/_work
- name: dind
image: docker:dind
securityContext:
privileged: true
volumeMounts:
- name: work
mountPath: /home/runner/_work
- name: dind-storage
mountPath: /var/lib/docker
volumes:
- name: work
emptyDir: {}
- name: dind-storage
emptyDir: {}
|
部署命令总结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
# 1. 安装 ARC Controller
helm install arc \\
--namespace action \\
--create-namespace \\
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set-controller
# 2. 创建 GitHub PAT Secret
kubectl create secret generic github-pat-secret \\
--namespace=action \\
--from-literal=github_token='your-pat-token'
# 3. 安装 Runner Scale Set(带 DinD)
helm install your-runners \\
--namespace action \\
-f arc-values-with-dind.yaml \\
oci://ghcr.io/actions/actions-runner-controller-charts/gha-runner-scale-set
# 4. 验证部署
kubectl get pods -n action
kubectl get ephemeralrunners -n action
|
问题排查清单
如果 workflows 卡在队列中,按以下步骤排查:
1. 检查 minRunners 配置
1
|
helm get values your-runners -n action
|
确保 minRunners: 0
2. 检查 listener 状态
1
|
kubectl logs -n action -l app.kubernetes.io/component=runner-set-listener --tail=50
|
查找 "totalAssignedJobs" 和 "totalIdleRunners"
3. 检查 ephemeral runners
1
|
kubectl get ephemeralrunners -n action
|
应该看到 status 为 “Running” 的 runners
4. 检查 pod 状态
1
|
kubectl get pods -n action -w
|
Pods 应该保持 Running 状态直到 job 完成
5. 验证 GitHub API
1
|
gh api /orgs/your-org/actions/runners
|
Runners 应该显示在列表中(即使 labels 为空)
6. 检查 workflow 配置
确保使用正确的 runs-on 值:
1
|
runs-on: your-runners # 使用 runner scale set 名称
|
监控和日志
查看 listener 日志
1
|
kubectl logs -n action deployment/your-runners-listener -f
|
查看 controller 日志
1
|
kubectl logs -n action deployment/arc-gha-rs-controller -f
|
查看 runner pod 日志(运行时)
1
|
kubectl logs -n action <runner-pod-name> -c runner -f
|
查看 DinD 容器日志
1
|
kubectl logs -n action <runner-pod-name> -c dind -f
|
性能调优建议
1. 资源配置
根据实际工作负载调整资源限制:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 轻量级任务
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1"
memory: "2Gi"
# Docker 构建任务
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "4"
memory: "8Gi"
|
2. 并发控制
1
2
|
minRunners: 0 # 按需启动,节省资源
maxRunners: 10 # 根据集群容量和并发需求调整
|
3. DinD 存储优化
对于频繁的 Docker 构建,考虑使用持久化存储:
1
2
3
4
|
volumes:
- name: dind-storage
persistentVolumeClaim:
claimName: dind-storage-pvc
|
总结
关键要点
- ARC 0.12.x 必须使用
minRunners: 0 - Ephemeral runners 需要在创建时就绑定到特定的 job
- Workflows 使用 runner scale set 名称 - 不要使用
self-hosted label
- DinD 需要 privileged 模式 - 确保 Kubernetes 集群允许 privileged containers
- Runner labels 为空是正常的 - 这是 ARC 0.12.x 的设计行为
成功指标
- ✅ Workflows 在 15-30 秒内开始执行
- ✅ Runner pods 保持 Running 状态直到 job 完成
- ✅ Docker 命令在 workflows 中正常工作
- ✅ Listener 日志显示 job 被正确分配和执行
参考资源
文档日期: 2025-10-15
ARC 版本: 0.12.1
Kubernetes 版本: v1.32.5
状态: ✅ 生产就绪