从连接层开始定位

云端 Mac 出现问题,按层排查,不靠猜

从 SSH、图形界面和文件传输,到 Xcode、Runner、fastlane 与节点网络,先用可复现的命令缩小范围,再决定修配置还是提交工单。

独享物理机 macOS 图形界面与命令行 四节点网络排查
由多台 Mac mini 物理节点与网络链路组成的工程集群
diagnose@mac-node — zsh

$ ssh -v "$MAC_USER@$MAC_HOST"

debug1: Authentication succeeded

$ xcodebuild -version

Xcode toolchain ready

$ scutil --dns | grep nameserver

Resolver path verified

首次接入

先完成一次可验证的 SSH 连接

在控制台打开对应实例,确认主机地址、登录用户名和初始凭据。首次连接只解决三件事:验证目标主机、进入系统、把后续登录切换到密钥。

  1. 01

    核对实例与本机环境

    先确认实例处于正常运行状态,并把控制台显示的主机地址与用户名分别写入本机环境变量。不要把密码、私钥或完整凭据写进仓库、聊天记录或自动化日志。

    export MAC_HOST="控制台显示的主机地址"
    export MAC_USER="控制台显示的用户名"
    test -n "$MAC_HOST" && test -n "$MAC_USER" && echo "connection variables ready"
  2. 02

    首次连接并核对主机指纹

    执行连接后,将终端显示的指纹与控制台信息核对。主机地址发生变化、重装后指纹变化,或本机保存了旧记录时,不要直接忽略警告,应先确认实例是否仍是同一台设备。

    ssh -v "$MAC_USER@$MAC_HOST"
    ssh-keygen -F "$MAC_HOST"
  3. 03

    生成并安装独立密钥

    建议为云端 Mac 单独生成 Ed25519 密钥,便于轮换和撤销。安装公钥后保留当前会话,再开启第二个终端验证密钥登录成功,确认无误后再结束原会话。

    ssh-keygen -t ed25519 -a 64 -f "$HOME/.ssh/macrents_build"
    cat "$HOME/.ssh/macrents_build.pub" | ssh "$MAC_USER@$MAC_HOST" 'umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys'
    ssh -i "$HOME/.ssh/macrents_build" "$MAC_USER@$MAC_HOST"
  4. 04

    固定客户端配置并做基线检查

    为该实例设置独立别名、密钥路径和保活参数。进入系统后记录 macOS 版本、磁盘余量、当前用户与系统时间,后续构建失败时可快速判断是否发生环境变化。

    sw_vers
    whoami
    date
    df -h /
    uptime

连接超时与认证失败不是同一类问题

超时通常先查本地网络、端口、节点路由和来源地址限制;出现 Permission denied 则先查用户名、密钥文件、文件权限与服务端授权记录。不要在认证错误时反复改 DNS,也不要在网络不通时持续重置凭据。

远程访问

按任务选择终端、图形界面或文件通道

构建和自动化优先使用 SSH;需要调试界面、模拟器或桌面工具时使用图形化远程桌面;批量同步项目与产物时使用可恢复的文件传输。

终端连接

适合拉取仓库、安装依赖、执行构建和管理常驻任务。连接不稳定时开启客户端保活,并用详细日志判断中断发生在握手、认证还是会话阶段。

ssh -vvv -o ServerAliveInterval=30 -o ServerAliveCountMax=4 "$MAC_USER@$MAC_HOST"

图形化远程桌面

从控制台进入图形访问入口,适合 Xcode 界面调试、模拟器观察和需要桌面交互的工具。卡顿时先降低画面分辨率与刷新频率,再比较终端延迟,区分画面编码问题与整条网络链路问题。

文件传输

少量文件可用 scp,大目录与构建缓存建议用 rsync。传输前排除派生数据、临时归档和依赖缓存,避免把可重建内容反复跨境传输。

rsync -azP --partial --exclude DerivedData/ ./project/ "$MAC_USER@$MAC_HOST:~/workspace/project/"

会话安全与断线恢复

长时间构建不要只依赖一个前台终端。使用会话管理器或 macOS 服务机制保持任务运行,定期把日志写入受控目录。离开项目时撤销不再使用的公钥和访问令牌。

tmux new -s build
tmux attach -t build
tail -n 200 "$HOME/logs/build.log"
构建工具链

Xcode 报错前,先确认当前实际使用的工具链

图形界面里看到的 Xcode 与命令行选中的开发者目录可能不是同一个版本。先记录路径、版本、SDK、模拟器与签名环境,再重跑最小构建命令。

基础检查命令

xcode-select -p
xcodebuild -version
xcodebuild -showsdks
xcrun simctl list devices available
xcrun --find swift
swift --version
security list-keychains -d user
security find-identity -v -p codesigning
A

开发者目录

xcode-select -p 应指向本次构建要求的 Xcode。路径不符时先停止 Runner,切换目录后再重新启动,避免正在运行的任务继承旧环境。

B

SDK 与模拟器

若目标 SDK 不在 -showsdks 输出中,修改项目参数不会补齐工具链。模拟器任务还应确认设备状态、运行时版本和磁盘空间。

C

签名身份与钥匙串

签名身份存在不等于自动化进程可以读取私钥。比较交互式终端与 Runner 服务的用户、钥匙串搜索列表及解锁状态。

D

最小构建复现

先固定工作区、scheme、configuration 和 destination,再禁用无关脚本。保留完整退出码与末尾日志,不要只截取最后一行错误。

set -o pipefail
xcodebuild -workspace Project.xcworkspace -scheme Project -configuration Release -destination 'generic/platform=macOS' clean build | tee "$HOME/logs/xcode-build.log"
printf 'exit_code=%s\n' "$?"
自动化接入

Runner 能注册,不代表构建环境已经可重复

自托管 Runner 与常驻代理都应固定运行用户、工作目录、工具链路径、缓存边界和密钥读取方式。先让一个最小任务稳定完成,再逐步恢复并发、缓存和分发步骤。

GitHub Actions

自托管 Mac Runner

在项目或组织设置中生成一次性注册信息,在云端 Mac 上以专用系统用户完成注册。标签至少区分操作系统、芯片档位和用途,工作流只把 macOS 任务路由到对应节点。

  • 注册完成后安装为常驻服务
  • 把构建目录与凭据目录分开
  • 每个任务清理临时签名材料
  • 先限制单并发,再评估队列
whoami
xcode-select -p
printenv | sort
df -h "$HOME"
GitLab CI

macOS Runner

注册时选择适合 macOS 的执行方式,并用受保护标签限制任务来源。服务用户必须能访问项目目录与所需钥匙串,但不应获得与构建无关的系统权限。

  • 核对标签与受保护分支规则
  • 缓存键加入工具链与依赖版本
  • 失败重试只用于瞬时网络步骤
  • 产物上传前记录校验值与大小
git status --short
git rev-parse HEAD
shasum -a 256 "$HOME/artifacts/app.zip"
du -sh "$HOME/build-cache"
常驻构建代理

服务化运行

自研代理或其他构建代理应交给 macOS 服务机制管理,明确启动用户、环境变量文件、标准输出与退出后的重启策略。不要依赖某个远程桌面会话一直保持连接。

  • 配置稳定且唯一的工作目录
  • 限制日志体积并保留失败上下文
  • 重启后自动恢复,但避免失败循环
  • 定期验证工具链与磁盘基线
launchctl list | grep build
ps aux | grep '[b]uild-agent'
lsof -nP -iTCP -sTCP:ESTABLISHED
tail -n 200 "$HOME/logs/agent.log"

推荐的最小接入顺序

  1. 环境探针:输出用户、Xcode 路径、版本、磁盘与工作目录。
  2. 仓库任务:只执行检出与依赖解析,确认网络和文件权限。
  3. 无签名构建:验证编译与测试,排除证书变量。
  4. 签名归档:接入受控钥匙串与必要环境变量。
  5. 产物上传:记录退出码、文件大小、校验值与上传日志。
  6. 并发扩展:观察 CPU、统一内存、磁盘读写和队列时间后再增加任务。
发布自动化

fastlane 失败时,按证书、权限、变量、日志分层

不要一开始就重装全部依赖。先确认失败发生在签名准备、归档、导出还是上传阶段,再针对该阶段收集输入、退出码与脱敏日志。

fastlane 常见问题、检查命令与判断方法
排查层 常见表现 先检查什么 处理原则
证书 找不到签名身份、身份数量为零 security find-identity -v -p codesigning 确认导入目标钥匙串、证书有效性与私钥是否配对
描述文件 标识符不匹配、能力项不一致 目标标识符、团队信息、所需能力与文件内容 不要混用不同项目或不同环境的描述文件
钥匙串权限 终端可构建,Runner 无法签名 运行用户、搜索列表、解锁状态和私钥访问控制 让自动化进程只访问本次任务需要的签名材料
环境变量 交互式执行成功,服务执行缺少参数 printenv 的脱敏差异与服务启动配置 显式注入变量,不依赖交互式 Shell 配置文件
上传日志 归档成功但上传中断或返回非零状态 完整退出码、重试次数、文件大小和网络时间线 先确认产物有效,再把上传问题与构建问题分开
为什么终端执行成功,Runner 中却提示找不到签名身份?

最常见原因是运行用户不同,或服务进程没有继承交互式会话中的钥匙串搜索列表。分别记录 whoamisecurity list-keychains -d user 与签名身份输出,再比较两种执行环境。不要通过放宽所有私钥权限来掩盖用户边界问题。

如何确认 fastlane 缺少的是环境变量,而不是项目配置?

在相同提交、相同 Xcode 路径与相同工作目录下,对交互式终端和 Runner 分别输出脱敏后的变量名列表。只比较变量是否存在,不打印令牌值。若变量完整,再检查工作目录、Shell 类型、依赖版本和执行用户。

提交 fastlane 问题时应保留哪些日志?

保留 lane 名称、失败阶段、完整退出码、Xcode 与 fastlane 版本、任务起止时间、末尾上下文和可复现命令。删除访问令牌、证书密码、私钥、会话信息与个人数据后再提交。只给一张最后一行报错的截图通常不足以定位问题。

四节点网络

新加坡、日本(东京)、韩国(首尔)、香港统一用同一组指标比较

节点选择应基于团队所在地、代码与依赖来源、产物去向和实际线路。不要只看一次延迟结果;至少比较往返延迟、丢包、DNS 解析与路由变化,并记录测试发生的时间范围。

SG

新加坡

适合面向东南亚的团队与依赖链路。若延迟突然增加,比较办公网络、移动网络和另一条出口线路,判断是否为本地运营商路径变化。

JP

日本(东京)

适合日本及东北亚项目。排查跨境连接时同时记录直连延迟、路由跳数和文件传输速率,避免只凭图形桌面的视觉流畅度判断。

KR

韩国(首尔)

适合韩国与邻近区域接入。若 SSH 可用但大文件速度不稳定,应检查丢包、路径 MTU、本地代理与并发传输数量。

HK

香港

适合亚洲跨境协作与多地团队。遇到特定网络可达、另一网络超时时,分别保存两条路由结果并注明来源网络类型。

延迟与丢包

短时测试用于确认是否可达,持续测试用于发现抖动与间歇丢包。将 $MAC_HOST 设置为当前实例地址后执行:

ping -c 20 "$MAC_HOST"
nc -vz -w 5 "$MAC_HOST" 22
traceroute "$MAC_HOST"

DNS 与本机解析

如果使用主机名连接,先确认解析结果是否稳定;如果直接使用地址仍失败,问题通常不在 DNS。记录本机当前解析器与查询结果:

scutil --dns
dscacheutil -q host -a name "$MAC_HOST"
dig "$MAC_HOST"

路由与接口

确认流量从预期接口发出,并检查本地 VPN、代理或多网卡是否改变默认路由。测试后恢复原网络设置,不要同时修改多项变量:

route -n get "$MAC_HOST"
netstat -rn
ifconfig
networkQuality

传输层验证

SSH 握手正常但传输慢时,用固定文件做重复测试,记录文件大小、耗时和客户端网络。不要用不同项目目录、不同压缩方式的结果直接比较:

time scp "$HOME/test-transfer.bin" "$MAC_USER@$MAC_HOST:~/"
shasum -a 256 "$HOME/test-transfer.bin"
ssh "$MAC_USER@$MAC_HOST" 'shasum -a 256 ~/test-transfer.bin'

所有节点全年 365 天正常运行

如果连接出现异常,按来源网络、目标节点、协议与时间范围收集证据。单次测速不能代表长期线路质量;同一测试至少在问题网络与一个对照网络各执行一次,才能判断问题位于本地出口、跨境路径还是目标连接层。

升级人工支持

带着可复现上下文提交工单

现有用户优先登录控制台提交工单,便于关联订单与实例。无法进入控制台时,可发送邮件至 support@macrents.com。两种方式都会进入同一支持流程。

工单中应包含

  • 订单号与受影响实例
  • 节点:新加坡、日本(东京)、韩国(首尔)或香港
  • 问题发生的时间范围与时区
  • 预期结果、实际结果与复现步骤
  • 客户端系统、网络类型与所用协议
  • 命令退出码和经过脱敏的相关日志
  • 已经执行过的排查步骤及结果

消息中不要发送

  • 任何私钥文件或私钥正文
  • 完整密码、访问令牌或会话信息
  • 证书密码与未加密签名材料
  • 包含用户数据的完整数据库或项目归档
  • 未经处理的个人信息与业务机密

日志中的主机地址可保留必要部分,但应移除令牌、密码、请求头、签名材料和个人数据。支持人员需要更多信息时,会在工单中明确说明最小范围。

提交后的处理路径

确认订单与实例 复核复现条件 定位连接或环境层 提供操作步骤 验证恢复结果

连接中断、实例无法访问或构建任务持续失败时,请注明业务影响范围。售前配置判断可直接邮件咨询;涉及已有订单、主机状态和日志的技术问题,优先使用控制台工单。

下一步

先选对配置,再把排障路径接入团队流程

三档均为独享 Mac mini 物理节点、非虚拟机。按构建并发、统一内存需求和租用周期选择方案;已有实例遇到问题,可直接登录控制台提交工单。