Корпоративный Mac CI: Command Line Tools и Xcode.app на bare metal Apple Silicon

Когда вы строите корпоративный пул на удалённом bare metal Apple Silicon, первый архитектурный развилка — ставить ли на ноды только Apple Command Line Tools или держать полный Xcode.app. Ответ не «всегда одно»: CLT экономит гигабайты на NVMe и упрощает обновления, но xcodebuild -archive, рантаймы симулятора и часть сценариев подписи ожидают именно дерево Developer вокруг выбранного Xcode. Ниже — приземлённое сравнение для эксплуатации, а не маркетинговый чеклист.

1. CLT-only: где выигрываете и где упираетесь в потолок

Набор CLT даёт компиляторы Swift/Clang, линковщик и базовый xcodebuild без тяжёлого GUI и без полного бандла IDE. На плотном пуле это означает меньше мусора в /Library/Developer, быстрее клонировать образ и проще автоматизировать security-патчи. Ограничения жёсткие: если пайплайн требует конкретные рантаймы iOS/watchOS, установленные через Xcode → Platforms, или шаги, которые неявно тянут ресурсы из Xcode.app/Contents/Developer, «облегчённый» хост начнёт ломаться в самый неудобный момент. Для чисто серверных swift build, линтеров и части unit-сборок CLT часто достаточно; для release Archive с полным набором SDK и симуляторных дестинаций безопаснее закладывать Xcode.app как эталонный корень.

Правило большого пальца: если в матрице CI есть хотя бы один destination «симулятор + конкретная OS», считайте, что вам нужен полный Xcode или отдельно документированный набор рантаймов, совместимый с вашей версией CLT.

2. Полный Xcode.app: симулятор, Instruments и предсказуемый корень Developer

Xcode.app поднимает стоимость диска и времени подготовки, зато выравнивает поведение с рабочими станциями разработчиков: один и тот же путь к Developer/usr/bin, штатные шаблоны проектов, доступ к Instruments и GUI-диагностике по VNC, если политика это допускает. Для параллельного Archive из нескольких репозиториев на одной физической машине полный Xcode обычно проще сопровождать: вы фиксируете DEVELOPER_DIR=/Applications/Xcode_16.2.app/Contents/Developer в каждом job, а не полагаетесь на глобальный xcode-select, который кто-то переключил вручную ночью. Рантаймы симулятора занимают десятки гигабайт каждый; на быстром NVMe это не катастрофа для IOPS, но критично для свободного места и снимков Тома APFS — планируйте отдельный том под CoreSimulator и регулярную уборку, иначе параллельные UI-тесты начнут падать от «disk almost full» раньше, чем от багов приложения.

3. Параллельный Archive из нескольких репозиториев и дрейф xcode-select

На bare metal без гипервизора вы часто запускаете несколько агентов или несколько контейнеров поверх одной macOS. Общий глобальный sudo xcode-select -s — источник гонок: job A переключил корень, пока job B линкует. Практичный паттерн — никогда не менять глобальный select внутри job, а экспортировать DEVELOPER_DIR и, при необходимости, отдельные DERIVED_DATA_PATH на NVMe для каждого workspace. Для монорепозитория с несколькими .xcworkspace добавьте уникальный суффикс к каталогу производных, чтобы линковщик не бился за блокировки. Если вам нужна матрица «купить или арендовать» и теги runner-ов под такой пул, сверьтесь с материалом Пул ресурсов Mac CI в 2026: параллельные сборки из нескольких репозиториев, повторное использование кэша и расширение диска.

4. NVMe: сравнение фактического следа CLT, Xcode и симуляторов

Ниже — типичный порядок величин для планирования (цифры зависят от версии Xcode и выбранных платформ, используйте как ориентир для бюджета диска, а не как SLA).

Компонент CLT-only Xcode.app + один толстый рантайм симулятора
Базовый toolchain и SDK в /Library/Developer Меньше, быстрее разворачивать Заметно больше: сам .app плюс сопутствующие данные
Симуляторные рантаймы и кэш устройств Частично доступны, но сценарии ограничены Десятки ГБ на рантайм; рост с каждой мажорной iOS
Параллельные Archive + DerivedData Меньше дублирования SDK, но выше риск несовместимости Нужен запас NVMe под несколько деревьев и артефакты IPA/dSYM

На узлах с агрессивным параллельным xcodebuild и удалёнными кэшами полезно заранее развести «холодное» хранилище Git и горячие каталоги компиляции — см. FAQ по Bazel, Gradle и NVMe для Mac CI.

5. Чеклист перед фиксацией стандарта образа

Прогоните список вместе с мобильной платформой и эксплуатацией — так образ переживёт апгрейд мажорной iOS.

  • Есть ли в матрице симуляторные UI-тесты и какие минимальные версии OS они требуют?
  • Можно ли запретить глобальный xcode-select и перейти на только DEVELOPER_DIR per job?
  • Выделен ли на NVMe отдельный том или каталог для DerivedData, симуляторов и артефактов с политикой TTL?
  • Согласована ли версия Xcode на CI с политикой notarization и внутренними сканерами ИБ?
  • Заложен ли запас диска на двойные неудачные Archive и мусор CoreSimulator между ночными прогонами?

Почему Mac mini на macOS остаётся практичным якорем для такого пула

Даже при жёсткой дисциплине образов вам нужен предсказуемый Apple Silicon с высокой пропускной способностью памяти и низким энергопотреблением в простое — здесь сильны Mac mini. Нативный macOS без прослойки гипервизора упрощает сценарии, где xcodebuild, симулятор и цепочка подписи должны вести себя как на настольной машине разработчика. Gatekeeper, System Integrity Protection и FileVault дают ИБ привычный язык для удалённых build-хостов, а компактный корпус и низкий шум облегчают размещение рядом с остальной инфраструктурой. В долгую это снижает совокупную стоимость владения по сравнению с «самосборными» ПК, где стоимость простоя и сопровождения драйверов часто недооценивают.

Если вы расширяете пул bare metal под параллельные Archive и симуляторы, Mac mini M4 остаётся разумной стартовой точкой: сначала дисциплина DEVELOPER_DIR и уборка NVMe, затем горизонтальное добавление нод вместо переплаты за простаивающие ядра. Чтобы сравнить модели и регионы выделенного железа рядом с вашим пулом CI, откройте главную страницу Macstripe и сверьте конфигурации с метриками диска и очередей, которые уже собирает ваш оркестратор.