给亚太与北美研发团队

从连接到出包的操作手册

整机已经开通,就从当前卡住的一步查起。连接、工具链、签名与流水线分开核验,把一次成功构建变成可重复的交付。

地址、端口、用户名与交付状态以控制台实例详情为准。本文命令中的环境变量需先替换为自己的配置,不包含真实连接凭据。

01 · 连到整机

先确认入口,再检查链路

SSH 负责命令行与自动化,VNC 负责图形界面。两者使用同一台独享物理机,但需要分别核对连接参数。

SSH:逐项核对交付字段

在控制台打开对应实例,读取主机地址、SSH 端口与用户名。先在本地确认私钥路径,再执行连接;不要把 VNC 端口填入 SSH 命令。

chmod 600 "$SSH_KEY"
ssh -i "$SSH_KEY" -p "$SSH_PORT" "$NODE_USER@$NODE_HOST"

首次连接时核对主机指纹;无法确认就先提交工单,不要直接关闭主机校验。出现超时,先检查本地网络与端口可达性;出现权限拒绝,检查用户名、密钥及实例上的公钥配置。

重装或更换整机后,指纹可能变化。确认实例确实发生变更后,再更新本地记录。

VNC:把桌面留给交互操作

用控制台提供的远程桌面信息连接,核对地址、端口与密码。首次进入后设置自己的访问密码,避免多人长期共用一份凭据。

桌面适合配置 Xcode、检查钥匙串和观察模拟器;持续构建交给 SSH 或 runner。若 SSH 正常而桌面异常,记录客户端报错与实例状态,按远程桌面这一层排查,不要先反复重启整机。

需要通过 SSH 隧道访问时,按实际 VNC 端口建立转发,连接客户端的本地端口:

ssh -N -L 5901:127.0.0.1:"$VNC_PORT" \
  -p "$SSH_PORT" "$NODE_USER@$NODE_HOST"

隧道需保持连接。是否启用及具体端口,以实例配置与团队访问策略为准。

节点:按操作位置选,不按项目归属选

5 个节点为新加坡、东京、首尔、香港、美国东部。交互式桌面优先靠近主要操作者;自动化构建还要考虑代码与依赖下载路径。跨区团队可分别设置就近的构建机,用明确的 runner 标签分流,不必让所有成员远程操作同一台桌面。

比较节点时,用相同客户端、网络和时间段记录连接往返、仓库拉取及一次完整构建。网络延迟不等于编译耗时,不把不同网络条件下的结果直接比较。

02 · 固定工具链

让分支对应明确的 Xcode 环境

先记录版本,再迁移签名。桌面里能编译,不代表 runner 的用户会话也已准备完成。

并存版本,不让任务互相切换

将不同版本的 Xcode 分别命名并放入应用程序目录。下面的 Stable 与 Next 是自定义应用名,执行前改成机器上的实际名称。完成首次启动、许可确认及所需平台组件安装,再接入流水线。

xcode-select -p
xcodebuild -version
xcrun --sdk iphoneos --show-sdk-version

sudo xcode-select --switch \
  /Applications/Xcode-Stable.app/Contents/Developer

全局切换会影响未显式指定工具链的任务。多分支并行构建时,优先在单个任务内设置环境变量,避免另一条流水线改掉正在使用的默认版本。

export DEVELOPER_DIR=/Applications/Xcode-Next.app/Contents/Developer
xcodebuild -version

证书、私钥与描述文件成套检查

在实际执行构建的 macOS 用户下导入签名证书与对应私钥,再按当前 Xcode 版本的签名设置安装描述文件。只有证书而没有私钥,不能完成代码签名。

security find-identity -v -p codesigning
xcodebuild -list -workspace App.xcworkspace

核对工程的团队标识、Bundle Identifier、签名方式与描述文件覆盖范围。先用同一用户手动完成一次 archive,再让 CI 执行相同命令,以区分工程配置与 runner 会话权限问题。

自动化建议使用专用钥匙串与受控的密钥注入流程。检查非交互会话能否访问签名身份,不把钥匙串口令、证书导出密码或私钥提交进仓库,也不要打印到构建日志。

先留下一份可复现的构建回执

下面以工作区和共享 scheme 为例。替换工程名称、scheme 与导出配置;导出配置需按项目签名和分发要求准备。把退出码、工具链版本与产物路径一起记录,不只截取成功提示。

xcodebuild archive \
  -workspace App.xcworkspace \
  -scheme App \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  -archivePath "$HOME/builds/App.xcarchive"

xcodebuild -exportArchive \
  -archivePath "$HOME/builds/App.xcarchive" \
  -exportPath "$HOME/builds/export" \
  -exportOptionsPlist ExportOptions.plist
03 · 接入持续构建

把任务交给固定的 macOS 用户

一台整机只租给一个客户,不代表任务天然互不干扰。构建用户、目录和队列仍需由团队明确约定。

GitHub Actions:注册后再服务化

在仓库或组织的 runner 设置中获取适合 Apple Silicon 的安装包与注册指令,在专用目录解压。使用该页面提供的临时令牌,按所属仓库或组织注册,不把令牌保存在脚本里。

./config.sh \
  --url "$RUNNER_URL" \
  --token "$RUNNER_TOKEN" \
  --labels pushmac,macos,arm64

./svc.sh install
./svc.sh start
./svc.sh status

工作流的 runs-on 与注册标签对应。先派发不含签名的测试任务,确认工具链、工作目录和权限,再加入发布任务。只让可信代码使用含签名资产的 runner。

服务命令需在 runner 安装目录运行;操作用户与服务用户保持一致。

GitLab Runner:明确执行器与工作目录

按团队的 GitLab 实例说明安装兼容的 runner,再使用实例提供的认证信息注册。macOS 原生构建可选择 shell 执行器;这意味着任务会以本机用户权限执行,应限制可触发项目与分支。

mkdir -p "$HOME/ci"
gitlab-runner register
gitlab-runner install --working-directory "$HOME/ci"
gitlab-runner start
gitlab-runner status

按提示填入团队实例地址、令牌、标签与执行器。配置文件可能包含认证信息,限制其访问权限;日志保留任务编号与错误栈,不输出环境中的秘密变量。

具体安装参数需与已安装的 runner 版本匹配,先检查本机帮助再执行。

自启检查包含“重启后的第一条任务”

macOS 用户级服务通常依赖用户登录会话,安装服务不等于未登录时也能执行签名任务。核实 runner 使用的 launchd 服务类型、登录条件与钥匙串可用性;不要为追求自启而绕过团队的访问控制策略。

在可控时段验证重启后的服务状态和一次完整构建。Fastlane 使用项目锁定的依赖执行,例如 bundle exec fastlane ios build,其中 lane 名以项目定义为准。跨时区接力时,把并发数与队列规则写清,避免两个 archive 共写同一产物目录。

04 · 保留可复用的工作

先拆分耗时,再决定扩展存储

分别记录依赖解析、编译、签名与导出耗时。同一提交、同一工具链下比较冷构建和热构建,才能判断缓存是否生效。

缓存按工程与工具链分区

独享整机可以在租期内保留 DerivedData、SPM 下载内容与 CocoaPods 缓存。不要让所有分支无区别地写入同一目录;按工程、工具链和任务类型划分路径,保留依赖锁文件。

xcodebuild archive \
  -workspace App.xcworkspace \
  -scheme App \
  -destination 'generic/platform=iOS' \
  -derivedDataPath "$HOME/ci-cache/App/stable/DerivedData" \
  -clonedSourcePackagesDirPath "$HOME/ci-cache/App/stable/SPM" \
  -archivePath "$HOME/builds/App.xcarchive"

Flutter 与 React Native 项目还需对齐各自工具版本及 iOS 依赖锁定状态。出现异常先保留失败日志,再针对相关缓存清理;把全量删除放进每次构建,通常会失去热构建收益。

把容量和内存问题分开处理

Push M4 S 为 M4 / 16GB / 256GB,适合单 App 日常 CI;Push M4 L 为 M4 / 24GB / 512GB,适合更高内存需求及多 target 构建。是否适合并行,仍需以项目实测峰值为依据。

+1TB SSD 适合依赖缓存、多个工具链与历史产物逐步占满系统盘的情况;+2TB SSD 适合需要保留更多工程缓存和 archive 的工作流。存储附加项不会增加统一内存,也不保证编译速度按容量提升。

df -h
du -sh "$HOME/ci-cache" "$HOME/builds"

先确定挂载路径,再迁移缓存并修改流水线变量。附加项不等于备份;归档、符号文件与重要配置仍应按团队策略保存独立副本。

05 · 账户与租期

把续费安排在发布节奏之前

计费周期、节点和付款状态以控制台返回为准。提交工单时带订单编号,不发送密码、私钥或完整银行卡信息。

按天起租与续费周期

支持按天、周、月、季计费。Push M4 S 为 $19.2/天、$51.8/周、$95.9/月、$260.8/季;Push M4 L 为 $39.7/天、$107.2/周、$198.5/月、$539.9/季。在控制台查看实例到期时间、续费入口与可用周期,不把日价乘算结果当成其他周期的目录价。

发布前先核对租期是否覆盖构建与验收。需要调整周期时,查看控制台对应操作和实际账单;不要假定已有付款会自动转换为另一种周期。

更换节点前的迁移准备

节点变更涉及新的网络入口与整机环境,不等同于修改一个地区标签。先通过控制台工单确认处理方式,再备份代码、签名资产、runner 配置和必要产物。不要假定本地文件、缓存或登录信息会自动迁移。

迁移完成后重新核对主机指纹、runner 标签和签名权限,完成一次构建验证,再停止旧环境的任务分发。

付款渠道与美元结算

仅支持 USDT-TRC20 与 Visa / Mastercard / Amex 银行卡,经 Stripe 处理,全部以美元(USD)结算。实际可用网关以后端返回为准。链上付款按当次订单的网络、收款信息与金额操作,避免重复使用旧订单信息。

付款后先查看订单状态。需要核对时,通过工单提供订单编号、付款时间与交易哈希或支付参考编号;不要再次付款来尝试刷新状态。

全年在线与项目备份

物理节点全年 365 天正常运行,机房负责电源、网络与散热,无计划停机。持续在线不替代项目备份,也不代表客户端网络不会中断。一次远程会话掉线时,先核对实例状态与另一种连接方式,再判断是否为主机异常。

租期结束后整机擦除再交付下一位客户。退租前导出所需代码、产物和配置,移除 runner 注册并撤销相关访问令牌,不把实例当成唯一存档位置。

继续整理构建流程

操作查手册,方案读技术文章

本页处理即时操作。迁移、缓存设计与跨时区分工,进入文章列表阅读完整上下文。

进入 PushMac 技术文章列表

从实际发布的文章中选择主题,查看完整步骤与适用条件。迁移工具链或改动缓存目录前,先记录现有配置,留出回退路径,再逐项验证。

手册中的命令以说明操作为目的;文章中的实践也需要结合仓库结构、签名策略与团队权限执行。

让工单带上可复查的构建记录

亚太与北美成员接力处理同一个问题时,明确时间和节点,比只写“连不上”更容易继续排查。

  1. 01

    定位实例

    写订单或实例编号、所用节点、发生时间与时区。不同成员使用不同网络时,分别注明连接位置。

  2. 02

    留下错误

    附客户端报错、构建命令、退出码、Xcode 版本与最后一段相关日志。截图或文本提交前先移除秘密信息。

  3. 03

    写明已查步骤

    说明 SSH 与 VNC 是否分别可用、问题是否可复现、最近改动了哪些配置,避免下一位处理人重复检查。

把检查回执交给支持团队

登录控制台提交工单,跟进实例与订单问题。无法登录时,发邮件至 support@pushmac.com,注明账户邮箱与问题范围。