终端连接
适合拉取仓库、安装依赖、执行构建和管理常驻任务。连接不稳定时开启客户端保活,并用详细日志判断中断发生在握手、认证还是会话阶段。
ssh -vvv -o ServerAliveInterval=30 -o ServerAliveCountMax=4 "$MAC_USER@$MAC_HOST"
从 SSH、图形界面和文件传输,到 Xcode、Runner、fastlane 与节点网络,先用可复现的命令缩小范围,再决定修配置还是提交工单。
$ ssh -v "$MAC_USER@$MAC_HOST"
debug1: Authentication succeeded
$ xcodebuild -version
Xcode toolchain ready
$ scutil --dns | grep nameserver
Resolver path verified
在控制台打开对应实例,确认主机地址、登录用户名和初始凭据。首次连接只解决三件事:验证目标主机、进入系统、把后续登录切换到密钥。
先确认实例处于正常运行状态,并把控制台显示的主机地址与用户名分别写入本机环境变量。不要把密码、私钥或完整凭据写进仓库、聊天记录或自动化日志。
export MAC_HOST="控制台显示的主机地址"
export MAC_USER="控制台显示的用户名"
test -n "$MAC_HOST" && test -n "$MAC_USER" && echo "connection variables ready"
执行连接后,将终端显示的指纹与控制台信息核对。主机地址发生变化、重装后指纹变化,或本机保存了旧记录时,不要直接忽略警告,应先确认实例是否仍是同一台设备。
ssh -v "$MAC_USER@$MAC_HOST"
ssh-keygen -F "$MAC_HOST"
建议为云端 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"
为该实例设置独立别名、密钥路径和保活参数。进入系统后记录 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 与命令行选中的开发者目录可能不是同一个版本。先记录路径、版本、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
xcode-select -p 应指向本次构建要求的 Xcode。路径不符时先停止 Runner,切换目录后再重新启动,避免正在运行的任务继承旧环境。
若目标 SDK 不在 -showsdks 输出中,修改项目参数不会补齐工具链。模拟器任务还应确认设备状态、运行时版本和磁盘空间。
签名身份存在不等于自动化进程可以读取私钥。比较交互式终端与 Runner 服务的用户、钥匙串搜索列表及解锁状态。
先固定工作区、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 与常驻代理都应固定运行用户、工作目录、工具链路径、缓存边界和密钥读取方式。先让一个最小任务稳定完成,再逐步恢复并发、缓存和分发步骤。
在项目或组织设置中生成一次性注册信息,在云端 Mac 上以专用系统用户完成注册。标签至少区分操作系统、芯片档位和用途,工作流只把 macOS 任务路由到对应节点。
whoami
xcode-select -p
printenv | sort
df -h "$HOME"
注册时选择适合 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"
不要一开始就重装全部依赖。先确认失败发生在签名准备、归档、导出还是上传阶段,再针对该阶段收集输入、退出码与脱敏日志。
| 排查层 | 常见表现 | 先检查什么 | 处理原则 |
|---|---|---|---|
| 证书 | 找不到签名身份、身份数量为零 | security find-identity -v -p codesigning | 确认导入目标钥匙串、证书有效性与私钥是否配对 |
| 描述文件 | 标识符不匹配、能力项不一致 | 目标标识符、团队信息、所需能力与文件内容 | 不要混用不同项目或不同环境的描述文件 |
| 钥匙串权限 | 终端可构建,Runner 无法签名 | 运行用户、搜索列表、解锁状态和私钥访问控制 | 让自动化进程只访问本次任务需要的签名材料 |
| 环境变量 | 交互式执行成功,服务执行缺少参数 | printenv 的脱敏差异与服务启动配置 | 显式注入变量,不依赖交互式 Shell 配置文件 |
| 上传日志 | 归档成功但上传中断或返回非零状态 | 完整退出码、重试次数、文件大小和网络时间线 | 先确认产物有效,再把上传问题与构建问题分开 |
最常见原因是运行用户不同,或服务进程没有继承交互式会话中的钥匙串搜索列表。分别记录 whoami、security list-keychains -d user 与签名身份输出,再比较两种执行环境。不要通过放宽所有私钥权限来掩盖用户边界问题。
在相同提交、相同 Xcode 路径与相同工作目录下,对交互式终端和 Runner 分别输出脱敏后的变量名列表。只比较变量是否存在,不打印令牌值。若变量完整,再检查工作目录、Shell 类型、依赖版本和执行用户。
保留 lane 名称、失败阶段、完整退出码、Xcode 与 fastlane 版本、任务起止时间、末尾上下文和可复现命令。删除访问令牌、证书密码、私钥、会话信息与个人数据后再提交。只给一张最后一行报错的截图通常不足以定位问题。
节点选择应基于团队所在地、代码与依赖来源、产物去向和实际线路。不要只看一次延迟结果;至少比较往返延迟、丢包、DNS 解析与路由变化,并记录测试发生的时间范围。
适合面向东南亚的团队与依赖链路。若延迟突然增加,比较办公网络、移动网络和另一条出口线路,判断是否为本地运营商路径变化。
适合日本及东北亚项目。排查跨境连接时同时记录直连延迟、路由跳数和文件传输速率,避免只凭图形桌面的视觉流畅度判断。
适合韩国与邻近区域接入。若 SSH 可用但大文件速度不稳定,应检查丢包、路径 MTU、本地代理与并发传输数量。
适合亚洲跨境协作与多地团队。遇到特定网络可达、另一网络超时时,分别保存两条路由结果并注明来源网络类型。
短时测试用于确认是否可达,持续测试用于发现抖动与间歇丢包。将 $MAC_HOST 设置为当前实例地址后执行:
ping -c 20 "$MAC_HOST"
nc -vz -w 5 "$MAC_HOST" 22
traceroute "$MAC_HOST"
如果使用主机名连接,先确认解析结果是否稳定;如果直接使用地址仍失败,问题通常不在 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'
如果连接出现异常,按来源网络、目标节点、协议与时间范围收集证据。单次测速不能代表长期线路质量;同一测试至少在问题网络与一个对照网络各执行一次,才能判断问题位于本地出口、跨境路径还是目标连接层。
日志中的主机地址可保留必要部分,但应移除令牌、密码、请求头、签名材料和个人数据。支持人员需要更多信息时,会在工单中明确说明最小范围。
连接中断、实例无法访问或构建任务持续失败时,请注明业务影响范围。售前配置判断可直接邮件咨询;涉及已有订单、主机状态和日志的技术问题,优先使用控制台工单。
三档均为独享 Mac mini 物理节点、非虚拟机。按构建并发、统一内存需求和租用周期选择方案;已有实例遇到问题,可直接登录控制台提交工单。