官方当前资料列出的 Machine Runner 3 支持 macOS X 11.2 及更高版本,并覆盖 Intel 与 Apple Silicon。这意味着,CircleCI Machine Runner 3 远程 Mac 部署可以落到真实的 Apple Silicon 主机上,但“Runner 在线”只能证明代理进程能通信,不能证明 Xcode、签名、重启恢复和清理流程已经达到生产要求。CircleCI Runner 平台支持说明
本周建议动作:先用无签名、可丢弃的测试项目完成资源类路由,再接入 Xcode 构建;最后执行一次计划内重启和工作区清理验收。标准化、无需固定工具链的任务继续使用托管执行器;只有需要固定 Xcode、访问私有依赖、连接内网或控制签名凭据时,才部署自托管 Runner。
维护 CircleCI iOS 或 macOS 流水线、需要固定工具链的开发者,适合看这篇。
需要接入签名、私有仓库或内网服务的 DevOps 工程师,适合看这篇。
负责远程 Mac 权限隔离、更新与故障恢复的平台维护者,也可以直接按时间线执行。
先判断任务是否值得迁移到远程 Mac
CircleCI self-hosted runner 的价值,不是把所有任务换到另一台机器,而是把执行环境的控制权交给你。官方说明中,Machine Runner 会直接安装在虚拟机或物理机上,任务就在该 Runner 所在的环境中执行。CircleCI 自托管 Runner 工作模型
这会带来几个现实限制:
- 环境不会自动变干净。 上一次任务留下的 DerivedData、依赖目录、临时文件或钥匙串状态,可能影响下一次构建。
- 权限边界由主机决定。 Runner 执行账户能访问什么目录、能否读取 Keychain、能否连接内网,不是 CircleCI 页面上的“在线”状态可以证明的。
- 工具链版本需要你维护。 Xcode、Command Line Tools、Homebrew、Ruby、Node.js 和 CocoaPods 的升级,都可能改变构建结果。
- 并发能力受真实主机限制。 单台 Mac 并不等于可以无限并行。多个任务共享 CPU、内存、磁盘和登录会话时,排队与资源争用会直接反映到流水线时间。
- 远程管理通道必须独立验证。 SSH 或网页控制台可用,不代表 Runner 的后台服务、Xcode 调用和重启后的自动恢复都正常。
因此,你可以按下面的条件分流:
- 若任务只需要 Linux 容器、标准依赖和普通单元测试,选托管执行器。
- 若任务必须使用固定 Xcode、真实 macOS SDK、私有网络或本机证书,选远程 Mac 上的 Machine Runner 3。
- 若一个流水线既有普通测试,又有 Xcode 打包,采用双轨流水线:普通任务留在托管环境,macOS 专属任务路由到远程 Mac。
第 0 小时:画出权限、目录和恢复边界
在远程 Mac 上不要直接使用日常管理员账户跑构建。先建立专用执行账户,例如:
sudo sysadminctl -addUser <ci-user> -password -
sudo mkdir -p /Users/<ci-user>/ci/{workdir,cache,logs}
sudo chown -R <ci-user>:staff /Users/<ci-user>/ci
<ci-user>、目录名和主机名都只是占位符。生产环境中应使用团队的账户管理流程,不要把真实密码写入脚本、仓库或构建日志。
建议把目录职责拆开:
| 目录 | 用途 | 默认处理方式 |
|---|---|---|
/Users/<ci-user>/ci/workdir |
当前任务源码与中间文件 | 任务后清理 |
/Users/<ci-user>/ci/cache |
可重建的依赖缓存 | 定期淘汰 |
/Users/<ci-user>/ci/logs |
Runner 与任务日志 | 限制权限并轮换 |
/Users/<ci-user>/ci/secrets |
不建议长期存放敏感凭据 | 尽量改用 Keychain 或临时注入 |
CircleCI 的 Machine Runner 3 使用配置文件定义认证、节点名称、工作目录和日志行为;官方配置参考还说明,环境变量可能优先于 YAML 配置,因此你需要检查系统服务环境,避免同名变量覆盖文件内容。Machine Runner 3 配置参考
这一阶段的停止条件很明确:如果你还不能回答“哪个账户执行、源码放在哪里、缓存能否删除、签名文件谁能读”,不要继续安装 Runner。
03第 1 小时:创建 namespace、resource class 和令牌
CircleCI 自托管 Runner 的任务路由依赖两个对象:namespace 和 resource class。一个组织只能声明一个唯一 namespace;resource class 则用于把特定任务匹配到对应的 Runner 池。namespace 与 resource class 规则
你可以通过网页界面创建,也可以使用 CircleCI CLI。命令中的内容全部使用占位符:
circleci namespace create <namespace> --org-id <organization-id>
circleci runner resource-class create \
<namespace>/<resource-class> \
"<description>" \
--generate-token
命名时保持简单。namespace 使用小写字母、数字、下划线或短横线;resource class 必须与仓库配置中的字符串完全一致,包括大小写。比如:
resource_class: <namespace>/<resource-class>
怎样给远程 Mac 设计 resource class?
把硬件、Xcode 版本和用途反映在资源类名称或描述中,例如 <namespace>/macos-xcode-build。如果后续还要增加不同 Xcode 版本或签名节点,可以分别创建不同资源类,避免普通测试任务误入发布节点。resource class 是路由标签,不是 CPU 或内存规格的自动申请器。Resource class 配置说明
令牌只在创建时显示一次。不要写入 .circleci/config.yml,也不要通过 echo 直接打印到日志。建议保存到受控的密码管理系统,并记录以下信息:
- 所属组织与 resource class;
- 创建人与创建日期;
- 当前使用的主机;
- 轮换责任人;
- 撤销后如何重新注册 Runner。
若令牌疑似泄露,先撤销或轮换,再重启对应 Runner。不要等到构建日志出现异常后才处理。
04第 2 小时:在真实 Mac 上安装并启动 Machine Runner 3
CircleCI 的 macOS 安装方式可能随 Runner 包和支持状态调整。安装时应以官方 macOS 安装指南当天显示的下载、校验和安装命令为准,不要长期复制旧博客中的安装包地址。
准备阶段先检查基础工具:
uname -m
sw_vers
which curl
which brew
which tar
然后按官方页面完成 Runner 包下载、校验和安装。校验失败、系统版本不在支持范围内,或下载包的签名和公证状态无法确认时,应停止,不要使用 --no-verify 一类方式绕过检查。
安装后配置以下字段:
api:
auth_token: <runner-auth-token>
runner:
name: "<runner-hostname>"
working_directory: "/Users/<ci-user>/ci/workdir"
logging:
level: "info"
format: "text"
上面的字段名用于说明结构,实际路径和启动方式以当前官方 macOS 页面为准。尤其要注意:Machine Runner 3 与旧版 Launch Agent 的文件名、服务管理方式并不应混用。官方已经将 Machine Runner 3 作为替代方案,旧命令只能用于排查历史安装。
macOS 无图形界面运行时,还要验证服务是否能在重启后加载。官方安装说明分别给出了 GUI 和非 GUI 会话的 launchctl bootstrap、enable、kickstart 与 print 流程。
首次启动后至少检查三处:
launchctl print user/$(id -u)/com.circleci.runner
ps aux | grep -i circleci
tail -n 100 <runner-log-path>
同时在 CircleCI 控制台的 Runner inventory 中确认节点名称和 resource class。控制台显示在线只是第一项证据;进程、服务状态、日志和 inventory 必须相互吻合。
05第 3 小时:先完成 Xcode 工具链验收,再接入正式项目
Apple 文档明确区分了完整 Xcode 与 Command Line Tools。xcodebuild 和 xctrace 随完整 Xcode 提供,不属于单独安装的 Command Line Tools 包。Apple 的 Command Line Tools 说明
因此,远程 Mac 上不要只执行:
xcode-select --install
就认为 Xcode CI 已经准备完成。先确认完整工具链:
xcode-select --print-path
xcodebuild -version
xcrun --find xcodebuild
xcrun simctl list devices
如果主机安装了多个 Xcode,明确选择构建版本:
sudo xcode-select --switch /Applications/<Xcode.app>
xcode-select --print-path
也可以只对单次任务使用 DEVELOPER_DIR,避免改变整台主机的默认工具链:
DEVELOPER_DIR="/Applications/<Xcode.app>" \
xcodebuild -version
Apple 文档说明,xcode-select --switch 需要管理员权限,而 DEVELOPER_DIR 可在调用命令时临时覆盖开发者目录。Xcode 命令行工具选择方法
自托管 Runner 调用 Xcode 时要检查什么?
在 job 中声明 machine: true,并填写刚创建的 resource class。最小验证配置如下:
version: 2.1
jobs:
verify-macos-runner:
machine: true
resource_class: <namespace>/<resource-class>
steps:
- checkout
- run:
name: Verify host and Xcode
command: |
whoami
sw_vers
xcode-select --print-path
xcodebuild -version
- run:
name: Build disposable project
command: |
xcodebuild \
-project <SampleProject>.xcodeproj \
-scheme <SampleScheme> \
-sdk iphonesimulator \
-configuration Debug \
build
workflows:
verify:
jobs:
- verify-macos-runner
CircleCI 官方配置参考要求使用 machine: true 和 resource_class: <namespace>/<resource-class>,任务才会路由到对应的自托管 Runner。
验收证据包括:
- job 日志中的
whoami; sw_vers和 Xcode 版本;- resource class;
xcodebuild退出状态;- 测试结果或构建产物;
- Runner 日志中的领取与回传记录。
如果任务停在 Preparing Environment,先检查 Runner 二进制执行权限、服务日志、出站网络和令牌状态。CircleCI 的排障文档也提示,macOS 首次安装可能遇到启动代理权限问题。Machine Runner 排障文档
第 4 小时:把普通构建、签名和发布拆开
签名任务不要和普通编译共用完全相同的权限。至少拆成以下两类:
- 无签名构建:只访问源码、依赖缓存和测试工具。
- 签名发布:额外访问临时 Keychain、证书、描述文件或发布所需凭据。
怎样隔离签名证书与构建账户?
最稳妥的做法是让非签名 job 使用低权限账户,把签名任务路由到单独 resource class,或者在同一主机上使用独立的临时 Keychain。不要把真实证书名称、团队账号、令牌或密码写进示例配置。
签名任务中应明确:
security create-keychain -p "<temporary-password>" <temporary-keychain>
security list-keychains -d user -s <temporary-keychain>
security default-keychain -s <temporary-keychain>
这里的密码和名称只能由安全注入机制提供。任务结束后执行清理:
security delete-keychain <temporary-keychain>
rm -rf "$HOME/Library/Developer/Xcode/DerivedData/<project-pattern>"
清理命令具有破坏性。执行前必须确认路径只指向当前任务生成的临时内容,并保留失败任务的日志和退出状态。不要为了“清理干净”直接删除整个用户目录或全局 Keychain。
若需要 UI 测试,还要单独处理 macOS 的辅助功能与应用控制权限。无头 CI 环境无法人工点击授权弹窗,因此应在上线前确认测试账户和系统权限已经按团队流程预配置。
07第 5 小时:执行重启、恢复和污染测试
重启远程 Mac 后,怎样确认 Runner 能继续工作?
不能只执行重启命令后看控制台状态。你需要验证服务是否自动加载、Runner 是否重新领取任务、Xcode 是否可调用,以及 SSH 或网页管理通道是否恢复。
建议按下面顺序操作:
- 先确认当前没有正在运行的生产发布任务。
- 保存 Runner 日志、inventory 状态和主机当前工具链信息。
- 执行计划内重启。
- 通过 SSH 或网页控制台重新连接。
- 检查
launchctl print、Runner 进程和最近日志。 - 重新提交无签名测试任务。
- 检查任务是否落到预期 resource class。
- 删除测试工作区,确认下一次任务不会读取残留文件。
- 运行一次 Xcode 构建和测试。
- 记录失败任务后的恢复步骤。
CircleCI 自托管 Runner 需要访问其 Runner 服务端点。官方支持资料要求确认到 runner.circleci.com 的出站连接,并使用 443 端口;网络策略、代理或 DNS 变化都可能让节点看似在线却无法领取任务。自托管 Runner 连接排查
下面这份清单可以作为上线门槛:
- ✅ inventory 中节点在线,名称与主机对应;
- ✅ 使用正确的 namespace 与 resource class;
- ✅ 非交互账户可以调用
xcodebuild; - ✅ Xcode 版本和项目要求一致;
- ✅ 任务失败后工作区、临时 Keychain 和敏感文件会清理;
- ✅ 重启后服务自动恢复;
- ✅ 令牌轮换后可以重新启动 Runner;
- ✅ SSH、日志和必要的远程管理通道可用;
- ❌ 只凭控制台在线状态直接迁移生产发布;
- ❌ 把签名证书和普通构建放在同一长期可读目录;
- ❌ 让构建脚本依赖某个工程师的图形化登录会话。
远程 Mac 部署的阶段对照与停止条件
| 阶段 | 你要完成的动作 | 可观察证据 | 未通过时的处理 |
|---|---|---|---|
| 任务选型 | 确认必须使用 macOS、Xcode、内网或签名 | 流水线分工文档 | 普通任务回退托管执行器 |
| 资源注册 | 创建 namespace、resource class 和令牌 | inventory、配置字符串 | 停止安装,先修正命名或权限 |
| 节点安装 | 安装 Runner 3 并建立服务 | 进程、日志、launchctl |
检查官方安装步骤与网络 |
| 首次构建 | 路由到远程 Mac 并执行 Xcode | job 日志、产物、退出码 | 不接入真实签名项目 |
| 发布接入 | 分离账户、Keychain 和发布资源 | 权限审计、清理日志 | 保持无签名构建 |
| 重启验收 | 重启后自动恢复并再次领取任务 | 恢复任务、Runner 日志 | 不允许生产上线 |
三种执行方案怎么选
| 方案 | 适合的任务 | 优点 | 主要代价 |
|---|---|---|---|
| CircleCI 托管执行器 | 标准化测试、普通构建、无需内网访问的任务 | 少维护主机,环境边界更清晰 | 工具链、网络和签名控制较少 |
| 远程 Mac 自托管节点 | 固定 Xcode、私有依赖、内网服务、签名发布 | 可控制真实 Mac 环境、账户和网络 | 需要维护更新、清理、重启与权限 |
| 双轨流水线 | 同时存在普通任务和 macOS 专属任务的团队 | 把维护成本限制在必要范围 | 路由、缓存和产物管理更复杂 |
如果你还没有可持续运行的真实 Mac 节点,可以先查看 Mac mini M4 租赁方案,再根据项目周期对照 Mac mini M4 租赁价格。选择节点时,优先确认是否满足你的 Xcode、网络、远程管理和持续运行要求,而不是只比较名义上的 CPU 参数。
10最后的上线判断
如果当前方案是本地 Mac 临时充当 Runner,常见缺点是:工程师关机或退出登录后任务中断;多人共用一台机器造成缓存与证书污染;硬件升级和故障恢复需要人工处理。如果改用普通 Linux 云主机,又无法直接提供完整 macOS、Xcode 和 Apple SDK 环境,跨系统绕行通常会增加维护脚本和排错成本。
因此,固定重负载、必须接物理设备或需要完全掌控硬件的团队,仍应考虑自购 Mac 并自行维护。若你的需求是按项目周期获得一台持续在线的真实 Mac,先部署无签名任务、完成重启恢复和工作区清理,再把生产流水线迁移到 VpsMesh 的远程 Mac,会比一开始就把签名发布任务直接放上去更稳妥。