症状:GitLab CI 需要构建 Apple 平台项目,但当前流水线没有 macOS 执行节点。
最快解法:GitLab Runner 可以安装在 macOS 上;先把它限制在专用、可信节点试跑,再决定是否上线。GitLab 将 Shell executor 标为维护模式,并明确其隔离有限,因此不要把共享节点或接收不可信代码的节点直接当作安全的生产 Runner。GitLab macOS 安装文档、Shell executor 文档。
这篇适合需要把 iOS 或 macOS 构建、测试交给 GitLab CI 的开发者。
如果你负责 DevOps 平台维护,重点看注册方式、用户会话和重启恢复。
如果你负责研发安全,重点核对 Shell executor 的隔离边界、签名凭据和节点准入条件。
SECTION 01第一阶段:先确认 Mac Runner 是否适合这条流水线
GitLab Runner 能安装在 macOS 上,常见用途是执行需要 Apple 工具链的任务,例如 Xcode 构建和测试;通用编排、纯脚本处理等任务,则不必全部迁到 Mac。先把流水线拆成两类:必须在 macOS 上运行的 Apple 平台任务,以及可以留在现有执行环境的通用任务。GitLab 的 macOS 文档列出 Apple Silicon 和 Intel 主机安装方式,并建议 iOS 与 macOS 构建使用 Shell executor。
Shell executor 会在安装 Runner 的主机上运行脚本,项目依赖也必须在该主机可用。它不会为每个任务创建独立、干净的执行环境:工作区、缓存、用户权限和主机上的其他资源,都需要你按节点用途管理。更重要的是,GitLab 将该执行器列为维护模式,只提供关键安全更新、不计划新增功能。GitLab 执行器状态说明。
| 任务或节点条件 | 建议判断 | 原因 |
|---|---|---|
| Apple 平台构建必须调用 Xcode,且节点专用、代码可信 | 可以先用 Shell executor 试跑 | GitLab 的 macOS 指南将 Shell executor 用于 iOS 和 macOS 构建 |
| 任务只做通用编排,不依赖 macOS 工具 | 留在现有通用执行环境 | 避免把不需要 Apple 工具链的任务一并迁移 |
| 多项目共享同一用户目录,或接收不可信代码 | 暂停接入 | Shell executor 隔离有限,任务以 Runner 用户权限运行 |
| 团队要求容器级隔离,但流水线直接依赖主机 Xcode | 不要把 Shell 当成隔离容器 | 先重新评估执行拓扑与工具链交付方式 |
GitLab 指出,Shell executor 的任务以 Runner 用户权限运行,可能影响同一服务器上的其他项目;官方安全建议是只运行可信构建。GitLab 自托管 Runner 安全说明。
SECTION 02第二阶段:建立独立节点与可追溯的 Xcode 基线
先给节点定边界,再装工具。不要把个人日常工作账户直接改成共享执行账户,也不要在未核对凭据的主机上运行外部贡献者或其他不可信分支的流水线。登记节点用途、允许使用它的项目、代码可信级别、管理责任人和回退入口;这几项不明确,就先不要注册 Runner。
接着确认项目要求的 macOS、Xcode、SDK、模拟器和依赖管理工具。Apple 说明,xcodebuild、simctl 等工具随 Xcode 提供,必须安装 Xcode 并将其设置为活动开发者目录后才能调用;单独安装 Command Line Tools 并不等于拥有完整 Xcode 工具链。Apple Xcode 命令行工具参考。
| 基线检查项 | 节点上执行的检查 | 验收记录 |
|---|---|---|
| 活动开发者目录 | xcode-select -p |
记录实际路径,并与项目指定的 Xcode 安装路径核对 |
| Xcode 版本 | xcodebuild -version |
保存任务日志中的版本信息,不凭安装目录名称推断 |
| 工具实际位置 | xcrun --find xcodebuild |
核对 CI 任务找到的命令路径 |
| 项目构建入口 | 核对 Workspace 或 Project、Scheme、SDK 与配置 | 将真实参数放进受控的构建脚本,避免假设默认 Scheme |
不要把安装完成当作工具链验收。若项目依赖模拟器、签名或额外平台组件,应在节点基线中单独记录并按项目实际需求验证;不要从“Runner 在线”推断这些能力已就绪。Apple 也将命令行工具包和完整 Xcode 区分开来;需要完整 Xcode 工具链时,应按项目要求安装并验证对应工具。Apple 命令行工具安装说明。
SECTION 03第三阶段:在登录会话中安装并注册 Runner
GitLab 的 macOS 服务模式是用户级 LaunchAgent,而不是系统级 LaunchDaemon:Runner 以当前已认证用户身份运行,用户登录后启动,用户注销时停止。它可以访问该用户的 Keychain 和图形会话,这对于某些模拟器或代码签名任务有用;但这也意味着它不能简单按“开机即作为系统服务运行”来设计。
按 GitLab 官方流程,以计划运行 CI 任务的 macOS 账户登录图形桌面,在本机终端安装 Runner。安装程序创建 LaunchAgent 配置并启动服务;注册时选择 shell,按项目或组的边界设置 Runner 范围和标签。注册令牌用环境变量或交互方式处理,不能写入仓库、公开日志或文档示例。注册完成后,配置保存在 Runner 的配置文件中;不要把真实令牌贴进排障记录。GitLab Runner 注册说明。
gitlab-runner register \
--url "<GITLAB_INSTANCE_URL>" \
--token "<RUNNER_AUTH_TOKEN>" \
--executor "shell" \
--description "<MAC_RUNNER_DESCRIPTION>"
命令里的地址、令牌和描述都是占位符。注册界面或项目配置中的标签要与后续 .gitlab-ci.yml 一致;如果标签不匹配,Runner 即使在线,也不会接到对应任务。
| 服务状态 | 你能观察到什么 | 运维含义 |
|---|---|---|
| 用户已登录 | LaunchAgent 随用户会话运行 | 可在此状态进行安装、注册和任务验证 |
| 用户已注销 | Runner 服务随用户会话停止 | 不应期待它像 LaunchDaemon 一样继续接单 |
| 主机重启后 | 需要重新观察登录与 Runner 服务状态 | 通过实测确认恢复;自动登录要先过安全审查 |
GitLab 文档提到,可通过 macOS 自动登录保持重启后的 Runner 可用;这不是无条件建议。自动登录可能让本机更容易进入已登录账户,应结合物理访问控制、账户权限和签名凭据风险评估。若团队不能接受这一取舍,就把登录会话依赖作为部署限制,而不是绕过服务模式自行假设它能以 LaunchDaemon 运行。
SECTION 04第四阶段:用最小任务验证调度、账户和 Xcode
先提交只用于验证的最小 CI 任务,确认标签匹配、仓库检出、Shell 执行账户和日志可见。以下示例不包含真实项目、标签、Scheme 或路径:
stages:
- verify
mac_environment_check:
stage: verify
tags:
- "<MAC_RUNNER_TAG>"
script:
- whoami
- pwd
- xcode-select -p
- xcodebuild -version
- xcrun --find xcodebuild
这一步只验证 Runner 是否调度成功,以及任务实际看到的账户和工具路径。它还不能证明项目构建成功。随后再按项目参数执行真实构建,例如替换成项目使用的 Workspace、Scheme、配置和目的地:
script:
- xcodebuild -workspace "<WORKSPACE_PATH>" -scheme "<SCHEME_NAME>" -configuration "<CONFIGURATION>" -destination "<DESTINATION>" build
不要把占位符原样当成可执行参数,也不要只看 GitLab 页面上的在线状态。任务日志里要能追溯 Runner 标签、检出目录、执行账户、活动 Xcode 路径和版本;真实构建还要以命令退出状态和流水线产物作为证据。Apple 的命令行工具文档说明,xcodebuild 用于构建 Xcode 项目和工作区;实际可用性仍须在目标节点和当前项目上核实。
SECTION 05第五阶段:扩大任务前审查工作区、Keychain 与签名资产
Shell executor 不是隔离容器。作业脚本以 Runner 用户权限运行;如果节点复用工作区或缓存,残留文件也会扩大跨任务影响。GitLab 安全文档提醒,非临时、多项目共用的 Runner 风险更高;工作区复用和凭据暴露都需要纳入评估。
在加进签名或发布任务前,逐项确认仓库访问范围、分支保护、Runner 可接收的项目、工作区清理方式、Keychain 中的证书与私钥,以及日志和工件是否会暴露敏感信息。尤其不要因为节点有签名资产,就把它开放给所有能提交 CI 脚本的项目成员;流水线会执行用户提供的代码,Shell executor 的风险可能延伸到 Runner 主机和网络。
✅ 只有可信项目能调度该节点,且节点用途与责任人已记录。
✅ 构建账户、工作区、缓存与 Keychain 的访问范围已核实。
✅ 测试任务未输出令牌、签名私钥或其他敏感值。
❌ 若节点要接收不可信代码,或多个不互信项目共享同一用户环境,先停止扩大使用范围。
❌ 若必须满足容器级隔离,不要把 Shell executor 包装成隔离容器;应先评估其他受支持的执行拓扑和 Apple 工具链运行方式。
SECTION 06第六阶段:注销、重启后复测,再决定上线或回退
验收时分开记录状态,避免把不同结果都写成“Runner 正常”。
| 验收层级 | 通过依据 | 不通过时的处理 |
|---|---|---|
| Runner 在线 | GitLab 中节点显示可用 | 检查进程、配置与登录会话 |
| 任务已调度 | 带目标标签的验证任务实际启动 | 核对标签、Runner 范围和项目权限 |
| Xcode 可用 | 任务日志中的活动路径与版本符合基线 | 修正活动开发者目录或安装所需工具 |
| 项目构建通过 | 真实项目命令成功,日志与产物可查 | 暂缓上线,检查 Scheme、依赖及构建参数 |
| 注销、重启后恢复 | 按团队要求执行会话与重启测试后,调度结果符合预期 | 记录为服务可用性限制,回退或调整部署方式 |
按计划分别测试用户注销、系统重启和 Runner 服务状态变化。每次都确认节点是否仍在线、任务能否被调度、活动 Xcode 是否保持预期,以及项目构建是否仍通过。GitLab 官方文档明确说明,macOS Runner 依赖登录用户会话,注销会停止服务;因此,不能用重启前成功的构建替代重启后验收。
上线判断清单:
- [ ] 节点仅承载经批准的可信项目,且执行账户没有超出任务所需的权限。
- [ ] Runner 标签、项目范围和注册配置已核对,未把令牌写入仓库或日志。
- [ ] CI 日志证明使用了预期的活动 Xcode,而不只是证明 Runner 在线。
- [ ] 真实项目构建或测试已通过,失败时有明确的回退入口。
- [ ] 注销和重启后的服务行为已经按团队要求复测。
- [ ] Keychain、签名资产、工作区残留和缓存的风险已由负责人确认。
缺少可信代码边界、凭据保护或重启恢复证据时,结论应是“继续隔离试跑”或“调整方案”,而不是共享上线。你的流水线还可以把 Apple 平台任务与通用任务分开调度:Mac 节点只接必须调用 macOS 工具链的任务,其他构建留在原有执行环境,减少不必要的主机暴露。
SECTION 07常见问题
macOS 主机能否直接承担 GitLab CI 节点?
可以,GitLab 提供 macOS 安装流程,并说明可在 Apple Silicon 和 Intel 主机上安装。对于需要 Xcode 的 Apple 平台构建,可使用 Shell executor;但部署前仍要检查维护状态、节点可信度和用户会话依赖。安装步骤完成只说明具备试跑条件,不等于构建、签名或重启恢复已经验收。
Apple 平台构建通常配置哪种执行器?
对直接依赖本机 Xcode 工具链的 macOS 构建,GitLab 文档指向 Shell executor;但它隔离有限且处于维护模式。应将其限制在专用、可信节点,而不是用来承载不可信脚本或互不信任项目。若团队的硬性要求是每个任务独立隔离,需要先评估其他执行拓扑是否能满足 macOS 工具链需求。
用户退出或 Mac 重启后,节点还能否继续接收任务?
GitLab 支持的 macOS Runner 以用户级 LaunchAgent 运行,用户登录时启动、注销时停止,不能把它当作开机即运行的 LaunchDaemon。重启后的实际可用性应在目标节点复测。自动登录可能帮助 Runner 在重启后恢复,但要先评估设备访问和账户安全;如果不接受该风险,就不要把自动登录设为默认条件。
如何核实 CI 实际调用了指定的 Xcode?
在 CI 日志中检查 xcode-select -p、xcodebuild -version 和 xcrun --find xcodebuild,再执行项目使用的构建命令。这样能把活动开发者目录、版本、命令路径与实际构建结果串起来。若版本或路径不符,应先修正节点基线;只有真实项目构建通过并留下可追溯日志,才算完成工具链验收。
完成节点准入和真实项目试跑后,如果你需要临时 Mac 算力或想评估持续 CI 节点,可以先阅读 MACNOX 远程 Mac 环境说明,并按实际所需周期核对 可用方案与计费信息。与继续使用现有 Linux 节点相比,Linux 无法直接提供 macOS 与 Xcode 工具链;与购买并自管 Mac 相比,仍需自行承担设备采购和维护。若你需要长期固定负载、物理接口或完全自主控制硬件,购置自有设备可能更合适;若只是临时搭建可信试运行环境,MACNOX 租赁可作为减少硬件采购和维护工作的选择,但不能替代你的安全验收。
SECTION 08常见问题 FAQ
GitLab Runner 能直接装在 macOS 主机上吗?
可以。GitLab 官方提供 macOS 安装流程,适用于 Apple Silicon 和 Intel 主机;iOS 与 macOS 构建可使用 Shell executor。安装成功并不等于安全或验收通过:你还要确认节点只接收可信任务、实际执行账户和 Xcode 工具链正确,并验证用户退出及重启后的 Runner 状态。
Mac 上的 GitLab CI 该用哪种 executor?
Apple 平台项目通常需要调用主机上的 Xcode、模拟器或签名环境,GitLab 文档建议这类 macOS 构建使用 Shell executor。但它处于维护模式,且不同任务之间隔离有限;适合专用、可信节点的试跑,不应被当作容器隔离方案。若必须隔离不可信代码,应先评估受支持的其他执行拓扑。
Mac 重启或用户注销后 Runner 会继续接任务吗?
macOS 上受支持的 GitLab Runner 服务以登录用户的 LaunchAgent 运行:用户登录后启动,注销时停止,因此不能按系统级 LaunchDaemon 理解。重启后是否恢复,需要在目标主机实测。自动登录可让服务在重启后恢复,但会带来本机访问风险;应按设备物理安全和凭据策略决定,而不是默认启用。
怎样证明 CI 任务使用了指定版本的 Xcode?
不要只看 Runner 显示在线。在 CI 日志中输出 `xcode-select -p`、`xcodebuild -version` 和 `xcrun --find xcodebuild`,确认活动开发者目录与团队基线一致;再运行项目实际使用的 `xcodebuild` 构建命令,并检查任务日志与构建产物。Xcode 已安装不代表活动路径选对,也不代表项目构建通过。