先接通,再迁移

三分钟连上你的云端 Mac

用 SSH 跑命令,用 VNC 操作 macOS 图形界面。整台独享物理机,非虚拟机;把源码、工具链与 CI 分批交接,不把本地环境的问题一起搬上去。

已有交付信息与 SSH 公钥时,可按下方顺序开始连接。首次配置工具链另需时间,不计入连接步骤。

先让 SSH 接通,后面的操作都走这条通道

准备本地终端、SSH 公钥和控制台中的主机信息。示例中的 HOST、PORT、USER 分别替换为交付的主机地址、SSH 端口和用户名,不要直接照抄。

01 · 本地准备

添加公钥,不上传私钥

已有专用密钥可直接使用。没有时,在自己的电脑生成一对 Ed25519 密钥,设置口令,再把 .pub 文件内容添加到控制台对应的 SSH 公钥配置中。

ssh-keygen -t ed25519 \
  -f ~/.ssh/osxbuild_ed25519

cat ~/.ssh/osxbuild_ed25519.pub

私钥留在本地。不要粘贴到工单、邮件或代码仓库;上传后按控制台提示确认公钥已应用到目标实例。

02 · 验证交付

用交付端口直连一次

从控制台实例详情取得连接信息。首次出现主机指纹确认时,先与可核验的交付信息对照;无法确认就提交工单,不要为跳过提示关闭主机校验。

ssh -i ~/.ssh/osxbuild_ed25519 \
  -p PORT USER@HOST

sw_vers
uname -m
xcodebuild -version

先确认系统、架构与 Xcode 版本。最后一条若提示工具链未就绪,先完成安装与路径选择,再接入构建任务。

03 · 固定入口

给机器一个本地别名

把下面内容写入本地 ~/.ssh/config。示例别名是 bake,后面的同步、隧道和排查命令都复用它,避免每次手填地址与端口。

Host bake
  HostName HOST
  Port SSH_PORT
  User SSH_USER
  IdentityFile ~/.ssh/osxbuild_ed25519
  IdentitiesOnly yes
  ServerAliveInterval 30
  ServerAliveCountMax 3

保存后执行 ssh bake。保活设置用于发现失效连接,不会替代网络重连,也不会让终端任务自动恢复。

图形桌面走 VNC,入口收进 SSH 隧道

需要配置 Xcode、检查钥匙串或查看模拟器时,再打开桌面。先确认控制台交付的 VNC 服务信息;不要把默认端口当作每台机器的连接参数。

客户端先选熟悉的

macOS 可使用系统“屏幕共享”;Windows 与 Linux 可使用支持 VNC 的 TigerVNC 客户端。客户端需要单独安装时,从其官方发行渠道获取,并确认支持交付服务采用的认证方式。

先降传输量,再调清晰度

先用 1440 × 900 或 1600 × 1000 的桌面尺寸起步,不必直接铺满高分屏。支持选择时优先试用 24 位色深;网络受限再尝试 16 位。可选项以客户端与服务端实际支持为准。

终端归档与远程桌面是两条使用路径。桌面拖动不够顺滑时,可继续通过 SSH 跑构建,再取回日志和 IPA,不必让整条流水线依赖画面刷新。

只把桌面端口映射到本机

在本地执行下方命令,保持该终端运行。VNC_PORT 替换为交付的服务端口;示例的 15900 是本地端口,可换成未被占用的端口。

ssh -N \
  -L 127.0.0.1:15900:127.0.0.1:VNC_PORT \
  -o ExitOnForwardFailure=yes \
  bake

随后在 VNC 客户端的地址字段填 127.0.0.1,端口字段填 15900。采用单一地址框的客户端,按其文档填写对应格式。

VNC 仍使用交付的桌面凭据认证,SSH 密钥不会替代桌面密码。完成后退出客户端,再用 Ctrl + C 关闭隧道。

桌面连不上,按连接链路逐段检查
现象 先检查什么 下一步
本地端口无法建立 SSH 是否已连通、本地端口是否被占用 换一个本地端口,并保留隧道终端中的错误信息
隧道已建立,桌面仍拒绝连接 交付的 VNC 端口与服务监听状态 核对实例详情,不额外向公网开放桌面端口
进入认证后失败 桌面用户名、密码及客户端认证兼容性 重新核对交付凭据;不要把 SSH 私钥当作 VNC 密码
能登录,但画面刷新慢 分辨率、色深、本地网络与节点距离 降低画面传输量,用 SSH 继续执行无需图形界面的构建

迁移按三批交接,不整盘照搬

数据先到位,工具链再对齐,最后接入 CI。每一步留一项验收结果;先跑通一次干净归档,再恢复缓存与自动化。

第一批 · 数据

同步源码,重建临时产物

用 Git 拉取项目,或用 rsync 同步本地工作目录与仓库外资源。首次不带 DerivedData 和旧 build 目录,也不把签名私钥混进普通文件同步。

rsync -az --progress \
  --exclude='DerivedData/' \
  --exclude='build/' \
  --exclude='*.p12' \
  --exclude='*.mobileprovision' \
  ./ bake:~/project/

验收:确认目标目录、提交版本和必要资源一致。示例不含删除参数,避免首次同步误删远端文件;不要把同步成功等同于已完成备份。

第二批 · 工具链

对齐版本,再恢复依赖

按项目需要安装或选择 Xcode,配置 Homebrew。CocoaPods 按锁文件恢复,SPM 先重新解析;缓存必须匹配工具链与依赖版本,不直接复用来源不明的目录。

xcode-select -p
xcodebuild -version
brew --version

bundle install
bundle exec pod install

验收:版本与本地基线一致,依赖可解析。仅 CocoaPods 项目执行最后两条。签名证书通过受控通道单独导入钥匙串,检查有效期与描述文件匹配关系。

第三批 · CI 接入

注册 runner,最后接分发

在 GitHub Actions 或 GitLab Runner 中注册专用执行器,先执行版本检查,再执行项目的 Fastlane lane。先验证 archive 与导出,最后添加上传步骤。

xcodebuild -list \
  -workspace App.xcworkspace

bundle exec fastlane ios build

验收:日志能追溯到提交版本、Scheme 和产物路径。示例的工作区与 lane 名需改为项目实际名称;发布凭据单独授权,不随源码分发。

接入 CI 时,让任务明确落到这台机器

自托管执行器使用你租用的物理节点。标签负责路由,凭据负责授权,两者不要混用。先让单个任务跑通,再评估并行数与磁盘占用。

GitHub Actions:用专用标签锁定构建机

按照仓库或组织设置中的指引注册 self-hosted runner,添加自定义标签 osxbuild。下面工作流检查工具链并生成归档,不包含签名材料注入、IPA 导出或分发。

name: iOS archive
on:
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: ios-${{ github.ref }}
  cancel-in-progress: false

jobs:
  archive:
    runs-on: [self-hosted, macOS, ARM64, osxbuild]
    steps:
      - uses: actions/checkout@v4
      - name: Check Xcode
        run: xcodebuild -version
      - name: Archive
        run: |
          xcodebuild \
            -workspace App.xcworkspace \
            -scheme App \
            -configuration Release \
            -archivePath "$RUNNER_TEMP/App.xcarchive" \
            archive

替换工作区与 Scheme,并确认 Scheme 已共享。仅允许可信仓库和可信任务使用持有签名材料的 runner;不同分支会生成不同并发组,仍需避免共享构建目录冲突。

Jenkins:通过 SSH 启动独立 agent

在 Jenkins 中新增固定节点,远程工作目录使用专门的构建目录,标签设为 osxbuild-mac。选择通过 SSH 启动 agent,填入交付主机与端口,私钥由 Jenkins 凭据库管理。

pipeline {
  agent { label 'osxbuild-mac' }

  stages {
    stage('Checkout') {
      steps {
        checkout scm
      }
    }
    stage('Toolchain') {
      steps {
        sh 'xcodebuild -version'
      }
    }
    stage('Build') {
      steps {
        sh 'bundle exec fastlane ios build'
      }
    }
  }
}

先确认 agent 所需 Java 可用、SSH 凭据有效、主机指纹已校验。通过 SSH 启动的非交互环境可能不会加载本地 shell 配置,因此 Homebrew、Ruby 与 Fastlane 的路径要显式配置。

GitLab Runner 也按同样顺序接入:注册执行器、限制可信项目、设置项目标签,再用版本检查任务验收环境。需要图形会话的测试,先单独验证运行条件。

先从一个执行槽起步。并行增加前,检查内存峰值、模拟器数量和 DerivedData 路径;不要让多个任务同时写同一份归档目录。

六个节点,先按操作机器的人来选

经常使用图形桌面,优先比较团队到节点的连接路径;主要跑 CI,再看源码、依赖和产物上传的路径。地理距离只是起点,实际体验还取决于运营商、路由与本地网络。

新加坡

SG · UTC+8

面向东南亚协作时区。白天经常远程操作 Xcode 的团队,可优先比较本地到该节点的连接表现。

选择新加坡节点

东京

JP · UTC+9

面向东亚协作时区。适合把日间交互开发与夜间归档安排在同一台机器上,减少环境交接。

选择东京节点

首尔

KR · UTC+9

面向东北亚协作时区。远程桌面使用较多时,先比较实际画面刷新与输入反馈,再固定团队入口。

选择首尔节点

香港

HK · UTC+8

面向华南与东南亚协作时区。关注远程交互,也要检查依赖下载与产物上传,避免只看一次连通结果。

选择香港节点

美国东部

US-E · UTC−5 / −4

面向北美东部与西欧协作。排 nightly 时使用明确的时区设置,注意夏令时带来的本地时间变化。

选择美国东部节点

美国西部

US-W · UTC−8 / −7

面向北美西岸协作。适合把构建窗口对齐当地工作日;跨时区交接时,在日志中保留明确的时间信息。

选择美国西部节点

两档机型均提供以上六个节点,实际可用状态以控制台实时返回为准。节点全年 365 天正常运行;本地网络中断与 SSH 会话断开,应与机器运行状态分开判断。

连通之后,把入口与签名材料收紧

先保留一条已经验证可用的连接,再调整访问策略。每次变更只做一项,确认新的连接成功后再关闭旧会话,避免把自己锁在机器外。

  1. 01

    验证密钥,再禁用密码登录

    先开第二个终端确认专用密钥可登录,再按系统的 SSH 配置方式禁用密码认证。配置变更前检查语法,并确认恢复连接的路径;不熟悉系统设置时先提交工单核对操作。

  2. 02

    端口只保留实际需要的

    按用途收敛远程登录与服务入口,VNC 优先走 SSH 隧道。避免把调试服务、构建控制接口或临时文件服务直接暴露到公网;绑定本地地址与访问控制要一起检查。

  3. 03

    密钥按人、按用途分开

    人工登录与 CI 使用不同密钥;人员变更或凭据疑似泄露时立即撤销旧授权。轮换时先添加并验证新公钥,再移除旧公钥,最后更新执行器与团队交接记录。

  4. 04

    签名资产不进入普通日志

    钥匙串按构建需要解锁,用完后收紧访问。API Key、证书口令与 match 解密凭据通过凭据系统注入;检查脚本是否回显敏感变量,不在仓库中保存私钥文件。

  5. 05

    到期前取回产物与配置

    把需要保留的源码、IPA、归档与流水线配置同步到团队自有存储,并验证文件可读。租期结束后的回收会涉及磁盘擦除与系统重装,不把机器本地目录作为唯一副本。

需要排查时,交接信息就够了。工单附订单号、节点、报错时间与时区,以及脱敏后的日志末尾 50 行。不要发送私钥、证书口令或账户密码;连接问题通过控制台工单或 support@osxbuild.com 联系。

连接路径定好,再交接下一次 archive

已有机器,先核对控制台中的交付信息。还没选配置,从两档独享云端 Mac 开始,按构建量决定机器,再按团队位置选节点。