Руководители платформы и iOS редко падают на SSH — они падают, когда тот же коммит дрейфует по неделям или сессиям на выделенном удалённом Mac. Этот гайд раскладывает воспроизводимые сборки на отпечатки Xcode, параллельные версии, политику DerivedData и изоляцию связки ключей, с таблицей сравнения, фрагментами shell и чек-листом перед запуском. Читайте вместе с материалами о раннере, SSH/VNC и сравнении с Xcode Cloud.
«Скомпилировалось» — наблюдение в точке времени. Воспроизводимость фиксирует состояние цепочки инструментов, разрешение зависимостей и вид материалов подписи в проверяемую базовую линию. Удалённые узлы добавляют переменные: обновления образов провайдера, следы нескольких пользователей и смесь ночных задач с интерактивной отладкой.
Шесть болевых точек, которые держат ревью честными:
Отпечатки только в чате: xcodebuild -version и swift --version не попадают в логи сборки, и доказать, какая цепочка работала, нельзя.
Дрейф xcode-select: обновления ОС или ручные переключения направляют ночные задачи на другой Xcode, меняя компилятор и краевое поведение подписи.
Перекрёстное влияние DerivedData: ветки делят префикс кэша, а инкрементальные сборки несут состояние макросов между контекстами.
Несовпадение вида связки ключей: интерактивные и CI-пользователи на одном хосте видят разные пути подписи — SSH работает, раннер нет.
Шум разрешений: запросы TCC останавливают headless-задачи таймаутами вместо ясных ошибок конфиденциальности.
Слишком агрессивная очистка: скрипты удаляют «похожие на кэш» папки и вынуждают несопоставимые холодные сборки.
Если два или больше повторяются за две недели, фиксируйте отпечатки на шаге один пайплайна и документируйте политику DerivedData и связки ключей в runbook — это управление узлом, а не байки про CI-вендора.
Считайте машину контрактным CI-узлом: зафиксируйте идентичность среды выполнения — пользователь CI, расклад домашнего каталога, корни инструментов, пути логов. Планируйте уровни диска заранее: несколько Xcode и симуляторы растут быстрее споров о CPU.
| Измерение | Общая интерактивная dev-машина | Выделенный удалённый Mac (приоритет CI) |
|---|---|---|
| Идентичность среды | Часто смешана с личными сессиями и GUI | Предпочтителен выделенный пользователь CI; разделите SSH/раннер и ручную отладку |
| Фиксация цепочки | Обновления следуют привычке человека | Закрепите минор Xcode, одобренный организацией; изменения через change control |
| DerivedData | Пути по умолчанию смешивают продукты | Разделяйте корни по репо или пайплайну; очистка должна быть проверяемой |
| Материалы подписи | Сертификаты разбросаны по login keychain | Отдельные связки ключей/пользователи или узлы; изолируйте релиз от экспериментов |
| Наблюдаемость | Зависит от памяти | Печатайте команды отпечатка в начале каждого лога сборки |
Воспроизводимость — это не «никогда не обновлять», а «каждое обновление уходит с отпечатками до/после и путём отката».
DerivedData ускоряет, пока не скрывает дрейф. Общий кэш подходит одной основной ветке с долгоживущими горячими кэшами; изоляция — экспериментальным веткам, модулям, чувствительным к ABI, или чистым сборкам недели релиза. Опишите политику вместо споров об удалении.
Корень на критический пайплайн: например ~/DerivedData/$REPO/$BRANCH_SAFE вместо неявных умолчаний.
Передавайте явно: внедряйте -derivedDataPath или переменные CI — без «чем был дефолт».
Сравните горячую и чистую перед релизом: один коммит должен отличаться только в ожидаемом коридоре.
Уровни очистки: отделите «безопасно чистить» от «вызовет огромные загрузки» с владельцами и ритмом.
Пороги диска: до красной линии свободного места переключайтесь на консервативное хранение или объектное хранилище.
Согласуйте с метками раннера: разные метки — разные корни кэша, чтобы релиз и эксперимент не конфликтовали; см. гайд по раннеру.
# Заголовок лога: отпечаток цепочки инструментов (пример)
xcodebuild -version
xcode-select -p
swift --version
/usr/bin/xcrun --show-sdk-path --sdk iphoneos
# Явный DerivedData (замените на вашу конвенцию repo/branch)
DERIVED="$HOME/DerivedData/${REPO_SLUG}/${BRANCH_SAFE}"
mkdir -p "$DERIVED"
xcodebuild -scheme "App" -destination 'platform=iOS Simulator,name=iPhone 16' \
-derivedDataPath "$DERIVED" build
Совет: при SwiftPM плюс Xcode фиксируйте также вывод swift package resolve или хэши lockfile, чтобы «тот же граф» не скрывал дрейф кэша резолвера.
Большинство сбоев headless-подписи — не «плохие сертификаты», а разные виды связки ключей или политики разблокировки, которые ни разу не выполнялись на безнадзорном пути. Минимум — сузить экспозицию, убрать интерактивную отладку с критического пути и разделить релиз.
Если GUI-отладка и раннеры должны делить железо, изолируйте метками или временными окнами и документируйте разовые одобрения VNC — та же идея, что сужение поверхности VNC в чек-листе SSH/VNC.
Предупреждение: не оставляйте приватные ключи дистрибуции в глобальных world-readable местах на общих удалёнках; предпочитайте отдельные учётки, узлы или файлы связки ключей и ротируйте при смене состава.
Диапазоны из публичных документов и полевой практики — используйте для выравнивания стейкхолдеров; биллинг и след проверяйте по контракту.
xcodebuild -version обычно секунды против времени компиляции, но окупается в разборе инцидентов.Ноутбуки и «одолженные» Mac экономят в краткосроке, но добавляют политики сна, запросы обновлений и смешанные сессии, ломающие контроль отпечатков и связки ключей. Вложенный macOS на Linux VPS часто жертвует Metal и стабильностью подписи. Для круглосуточно предсказуемой среды, проверяемой изоляции и диска по контракту в iOS CI/CD и агентах автоматизации выделенный удалённый Mac обычно ближе к продакшен-реальности. Аренда облачного Mac mini NodeMini подходит под этот след: выберите регион и диск, укрепите SSH для автоматизации и трактуйте отпечатки и политику кэша как переносимые операционные активы.
Статья о раннере — очереди, метки и workflow. Эта — внутренности узла. Соедините основную линию с гайдом по раннеру и примените здесь отпечатки и правила кэша.
Сравните SKU на странице цен аренды и добавьте внутренний запас под два Xcode и хранение DerivedData.
Начните со справочного центра, затем сверьте xcode-select и учётные записи подписи с этим чек-листом.