为什么选择自托管 Runner?
GitHub Actions 提供托管 Runner(ubuntu-latest、macos-latest 等),但对于 iOS/macOS 团队而言存在以下限制:
| 对比维度 | GitHub 托管 Runner | 自托管 Runner(远程 Mac) |
|---|---|---|
| macOS 版本控制 | 固定版本,滞后较多 | 自定义,与本地一致 |
| Xcode 版本 | 仅预装有限版本 | 可安装任意版本 |
| 依赖缓存复用 | 每次构建重新拉取 | 本地持久化缓存 |
| 私有网络访问 | 不支持 | 通过 VPN/内网直连 |
| 并发 Job 数 | 受账号套餐限制 | 按节点数自由扩展 |
| 月度费用 | 大量 macOS 分钟消耗成本高 | 固定租用成本,可预测 |
对于月均 iOS 编译超过 200 次、或需要 Xcode 15+、M 系列芯片原生 ARM 编译的团队,自托管 Runner 是更经济的选择。
前置条件
在开始前,请确认以下条件已满足:
- 远程 Mac:macOS 12(Monterey)或更高版本,推荐 M 系列芯片;SSH 或 VNC 可访问。
- GitHub 权限:Repository 管理员权限(添加 Runner 需要 Settings 页访问权);或 Organization 管理员权限(添加 Org 级别 Runner)。
- 磁盘空间:Runner 本身约占 500 MB,加上 Xcode 和 DerivedData 建议预留 ≥ 60 GB 空闲。
- 网络:Mac 可访问
github.com、api.github.com、ghcr.io;若在国内,建议配置代理或镜像(见后文)。 - 用户权限:Runner 建议以非 root 专用用户(如
ci-runner)运行,避免权限过大。
安装与注册步骤
以下步骤在远程 Mac 的终端(通过 SSH 或 VNC)中执行。
在 GitHub 获取注册令牌。进入仓库(或 Organization)的 Settings → Actions → Runners → New self-hosted runner,选择 macOS,复制页面中的下载链接和 --token 参数。令牌有效期 1 小时,请及时使用。
创建专用目录并下载 Runner 包。
mkdir ~/actions-runner && cd ~/actions-runner
# 替换为 GitHub 页面提供的最新版本链接(以 arm64 为例)
curl -o actions-runner-osx-arm64.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.315.0/actions-runner-osx-arm64-2.315.0.tar.gz
tar xzf ./actions-runner-osx-arm64.tar.gz注册 Runner(配置名称与标签)。将 YOUR_TOKEN 替换为第 1 步中复制的令牌。
./config.sh \
--url https://github.com/YOUR_ORG/YOUR_REPO \
--token YOUR_TOKEN \
--name "mac-mini-m4-node-1" \
--labels "self-hosted,macOS,ARM64,xcode15,m4" \
--work _work \
--unattended标签(--labels)是 workflow 文件中 runs-on 的匹配依据,建议包含:self-hosted(必选)、macOS、芯片类型(ARM64/X64)、Xcode 版本、节点编号。
安装为 launchd 服务(开机自启)。运行安装服务脚本,Runner 会以 launchd 守护进程方式常驻后台,Mac 重启后自动恢复。
sudo ./svc.sh install
sudo ./svc.sh start
# 验证状态
sudo ./svc.sh status在 GitHub 确认在线。回到 Settings → Actions → Runners,新注册的 Runner 状态应显示 Idle(空闲)。若长时间显示 Offline,检查 Mac 网络或代理配置。
标签策略与 Workflow 配置示例
合理的标签策略让不同 Job 路由到正确的 Runner,避免 Xcode 版本冲突或节点超负荷。推荐约定:
macOS,ARM64:M 系列芯片节点,速度快,适合原生 Swift/Obj-C 编译。xcode15、xcode16:指定 Xcode 主版本,避免意外版本漂移。node-1、node-2:节点编号,方便定向调试特定机器。
Workflow 示例(.github/workflows/ios-build.yml):
name: iOS Build & Test
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
build:
runs-on: [self-hosted, macOS, ARM64, xcode15]
timeout-minutes: 30
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Select Xcode
run: sudo xcode-select -s /Applications/Xcode_15.4.app/Contents/Developer
- name: Cache DerivedData
uses: actions/cache@v4
with:
path: ~/Library/Developer/Xcode/DerivedData
key: derived-data-${{ runner.os }}-${{ hashFiles('**/*.xcodeproj/project.pbxproj') }}
restore-keys: derived-data-${{ runner.os }}-
- name: Build
run: |
xcodebuild -project MyApp.xcodeproj \
-scheme MyApp \
-sdk iphonesimulator \
-configuration Debug \
CODE_SIGNING_ALLOWED=NO \
build | xcpretty
- name: Test
run: |
xcodebuild test \
-project MyApp.xcodeproj \
-scheme MyApp \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 15' \
CODE_SIGNING_ALLOWED=NO | xcpretty并发 Job 与资源限制配置
单台 Mac Mini M4(16 GB 统一内存)通常可稳定承载 2–3 个并发编译 Job;若 Job 包含 Simulator 测试,建议限制为 2 个并发。
Runner 侧:多 Runner 实例并行。在同一台 Mac 上,可注册多个 Runner 实例(每个使用不同工作目录)实现并发:
# 第二个 Runner 实例
mkdir ~/actions-runner-2 && cd ~/actions-runner-2
tar xzf ../actions-runner/actions-runner-osx-arm64.tar.gz
./config.sh \
--url https://github.com/YOUR_ORG/YOUR_REPO \
--token YOUR_TOKEN \
--name "mac-mini-m4-node-1-slot2" \
--labels "self-hosted,macOS,ARM64,xcode15" \
--work _work2 \
--unattended
sudo ./svc.sh install && sudo ./svc.sh startWorkflow 侧:并发控制。使用 concurrency 字段防止同一分支重复触发:
concurrency:
group: ios-build-${{ github.ref }}
cancel-in-progress: true资源监控建议:在 Runner 上安装轻量监控(如 htop),观察并发编译期间内存和 CPU 使用率。若内存压力过大,可调整 DerivedData 清理频率:
# 每周自动清理 DerivedData(加入 crontab)
0 3 * * 0 rm -rf ~/Library/Developer/Xcode/DerivedData/*常见报错与排查
以下是最常见的几类问题及快速定位方法:
Runner 显示 Offline / 无法上线:检查 Mac 是否可访问 https://api.github.com(curl -I https://api.github.com);确认 launchd 服务状态(sudo ./svc.sh status);检查 ~/actions-runner/_diag/ 下的日志文件。
Job 排队但不启动:确认 workflow 中 runs-on 的标签与 Runner 注册标签完全匹配(大小写敏感);检查 Runner 是否处于 Idle 而非 Busy 状态;若用 Org Runner,确认仓库有访问权限(Settings → Actions → Runner groups)。
xcodebuild 失败:xcode-select 指向错误:运行 xcode-select -p 确认当前 Xcode 路径;用 sudo xcode-select -s /Applications/Xcode_XX.app/Contents/Developer 切换;确认 Xcode 已执行初始化(首次启动需接受许可协议)。
网络拉取依赖超时(npm/CocoaPods/SPM):参考 MacPull 博客中的跨境 CI 镜像加速指南,为 Runner 环境配置镜像源或代理,并在 workflow 中通过 env: 传递代理变量。
磁盘满导致构建失败:DerivedData 和 Simulator 运行时会快速消耗磁盘。配置自动清理(见上节 crontab);或在 workflow 中加入清理步骤:xcrun simctl delete unavailable。