GitHub Actions 自托管 Runner(self-hosted runner)让你的 CI 工作流直接运行在远程 Mac 上,解决 GitHub 托管 Runner 不支持 macOS 原生 Xcode 编译、Simulator 测试以及私有网络访问等痛点。本文提供可复现的完整步骤:从在远程 Mac 上注册 Runner、配置标签与并发策略,到编写 workflow 文件与常见故障排查。

为什么选择自托管 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.comapi.github.comghcr.io;若在国内,建议配置代理或镜像(见后文)。
  • 用户权限:Runner 建议以非 root 专用用户(如 ci-runner)运行,避免权限过大。

安装与注册步骤

以下步骤在远程 Mac 的终端(通过 SSH 或 VNC)中执行。

1

在 GitHub 获取注册令牌。进入仓库(或 Organization)的 Settings → Actions → Runners → New self-hosted runner,选择 macOS,复制页面中的下载链接和 --token 参数。令牌有效期 1 小时,请及时使用。

2

创建专用目录并下载 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
3

注册 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 版本、节点编号。

4

安装为 launchd 服务(开机自启)。运行安装服务脚本,Runner 会以 launchd 守护进程方式常驻后台,Mac 重启后自动恢复。

sudo ./svc.sh install sudo ./svc.sh start # 验证状态 sudo ./svc.sh status
5

在 GitHub 确认在线。回到 Settings → Actions → Runners,新注册的 Runner 状态应显示 Idle(空闲)。若长时间显示 Offline,检查 Mac 网络或代理配置。

标签策略与 Workflow 配置示例

合理的标签策略让不同 Job 路由到正确的 Runner,避免 Xcode 版本冲突或节点超负荷。推荐约定:

  • macOS,ARM64:M 系列芯片节点,速度快,适合原生 Swift/Obj-C 编译。
  • xcode15xcode16:指定 Xcode 主版本,避免意外版本漂移。
  • node-1node-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 start

Workflow 侧:并发控制。使用 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.comcurl -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

总结与下一步

完整流程:获取注册令牌下载并安装 Runner配置标签注册 launchd 服务编写 workflow 文件配置并发与缓存。一台租用的远程 Mac Mini M4 可同时承载 2–3 个并发编译 Job,相比 GitHub 托管 macOS Runner 大幅降低月度 CI 费用,且支持稳定的 Xcode 版本控制和私有网络访问。如果你需要一台 7×24 在线、可随时 SSH 连接的远程 Mac 来运行 CI,欢迎查看 价格页面立即购买,也可浏览更多 技术博客文章

在远程 Mac 上跑 GitHub Actions CI

租用 Mac Mini M4,部署自托管 Runner,享受稳定 Xcode 环境与持久化依赖缓存。SSH/VNC 随时连接,无需登录即可查看价格和购买。