Если единственный Mac выходит на обслуживание, публикация iOS-приложения останавливается вместе с ним.
Быстрое решение: не превращайте второй Mac в периодическую резервную копию — обычные сборки и тесты распределяйте между одинаково подготовленными узлами, а производственную подпись выводите в отдельный основной и резервный контур.
Текст актуален на 20 сентября 2026 года; сведения о статусе Xcode 27 и требованиях сверены с публикацией Apple о выпуске Xcode, системными требованиями Xcode и заметками к выпуску Xcode 27.
Эта статья нужна вам, если у компании сейчас только один Mac-сервер сборки и любое обслуживание прерывает выпуск. Она также предназначена для платформенной команды, которая переносит production-пайплайн на Xcode 27, и для CTO или технического директора, выбирающего между второй физической машиной, резервным удалённым Mac и сохранением текущего риска.
Xcode 27 и границы отказоустойчивости
14 сентября 2026 года Apple выпустила Xcode 27. На дату проверки App Store Connect принимает приложения, собранные с Xcode 27 и соответствующим официальным SDK; это следует учитывать при планировании production-пула, а не смешивать с предварительными версиями Xcode 27.1 и Xcode 27.2. Проверяйте актуальные ограничения через официальные правила загрузки сборок в App Store Connect.
Второй Mac устраняет только часть рисков. У вас по-прежнему могут остаться общие точки отказа:
- CI-контроллер или очередь заданий недоступны, поэтому оба узла физически работают, но не получают задачи;
- сеть, DNS, VPN или исходящий доступ к Apple недоступны для обеих машин;
- сертификат, закрытый ключ, профиль provisioning или учётная запись подписи повреждены либо отозваны;
- хранилище артефактов и журналов является общим и выходит из строя вместе с CI;
- на обеих машинах установлена одна несовместимая версия Xcode или одинаково повреждён кэш;
- ручной запуск подписания зависит от конкретного имени хоста и локального пользователя.
Поэтому архитектуру нужно оценивать не по количеству Mac, а по независимости доменов отказа. Локальная пара в одной стойке помогает при отказе одной машины, но почти не защищает от проблем общего питания, сетевого сегмента, ошибочного обновления или компрометации общего секрета. Узлы в разных местах расширяют защиту, однако добавляют задержку, различия в доступе к ресурсам и больше операционных процедур.
Сколько Mac нужно для сервера сборки Xcode 27
Одного ответа для всех компаний нет. Для фиксированной постоянной нагрузки разумна пара узлов: оба принимают обычные задания, но production-подпись выполняется через изолированный основной путь с подготовленным резервом. Если нагрузка возникает главным образом перед релизами или команда мигрирует с другой версии Xcode, базовый узел можно дополнить удалённым Mac на время пиков и испытаний.
Второй узел не нужен как автоматическая гарантия доступности, если CI-контроллер, хранилище и подпись остаются общими и не имеют проверенного плана восстановления. В таком случае вы покупаете дополнительное оборудование, но сохраняете прежнюю единственную точку отказа.
Метрики архитектуры двух узлов
Удобнее принимать решение через измеряемые признаки: для каждого риска фиксируются доказательства, условие прохождения и причина отказа. Это превращает разговор о высокой доступности в проверяемый контракт между платформенной командой, безопасностью и владельцем релиза.
| Метрика | Базовая проверка | Проходит | Нельзя принимать |
|---|---|---|---|
| Независимость отказа | Отдельно описаны хост, сеть, контроллер, хранилище и подпись | Отказ одного домена не останавливает минимальный релизный путь | Второй Mac зависит от того же незащищённого ресурса |
| Совместимость среды | Зафиксированы архитектура Apple Silicon, macOS, Xcode, SDK и инструменты зависимостей | Один и тот же commit даёт сопоставимый результат на обоих узлах | Различия объясняются локальной настройкой |
| Маршрутизация | Есть правила по меткам, очередям и уровню доверия | Задание попадает только на разрешённый пул | Production-задача может случайно уйти на общий runner |
| Изоляция подписи | Ключи, Keychain и сервисные учётные данные разделены | Подписывающий узел получает минимально необходимый доступ | Для быстрого переключения копируется весь Keychain |
| Восстановление | Есть журнал переключения и обратного перехода | Команда подтверждает сборку, подпись, публикацию и возврат | Невозможно доказать, что резерв действительно готов |
| Экономика | Считаются простой, обслуживание, обновления и пиковая ёмкость | Выбранная модель соответствует характеру нагрузки | Сравнивается только цена Mac без эксплуатации |
Для оценки можно присвоить каждому пункту статус «пройдено», «с ограничениями» или «отклонено». Итоговое решение принимает не среднее значение: один провал в подписи или хранилище может заблокировать весь production-контур, даже если остальные метрики выглядят хорошо.
Базовая среда и контроль дрейфа
Xcode 27 нельзя считать одинаково установленным только потому, что на двух машинах отображается одно название приложения. Зафиксируйте в машинно-читаемом baseline:
- модель и архитектуру Mac;
- версию macOS и её совместимость с нужным выпуском Xcode;
- точный build Xcode 27, используемый в production;
- версии SDK, Swift, Ruby, Python, Java и инструментов управления зависимостями, если они участвуют в пайплайне;
- настройки проекта, скрипты, переменные среды и параметры симуляторов;
- способ получения кэшей, артефактов и зависимостей;
- состояние Keychain и контекст пользователя, в котором выполняется подпись.
Требования к операционной системе и оборудованию нельзя заменять внутренней таблицей команды: сверяйте их с официальной страницей Apple о системных требованиях Xcode. Release Notes нужны для проверки изменений поведения и ограничений конкретного Xcode 27, а не только для чтения списка новых функций.
Не копируйте образ первой машины на вторую как единственный способ синхронизации. Такой подход переносит скрытые настройки, устаревшие сертификаты, локальные пути и повреждённые кэши. Надёжнее описать среду в скриптах, зафиксировать версии зависимостей и автоматически проверять baseline перед допуском узла в production.
Какие переменные среды нужно синхронизировать на резервном Mac
Синхронизировать нужно воспроизводимое состояние, а не секреты без разбора. Исходный код, lock-файлы, скрипты, настройки сборки, версии инструментов и публичные параметры могут восстанавливаться из репозитория или системы управления конфигурацией. Кэши следует считать ускорителем, а не единственным источником результата.
Проверьте одинаковым commit:
- успешность компиляции;
- тесты и тестовые устройства;
- содержимое и контрольные суммы артефакта;
- предупреждения и логи;
- этап экспорта;
- этап подписи;
- загрузку в App Store Connect и итоговый статус.
Apple отдельно описывает статусы загрузки сборок в справочнике App Store Connect. Это полезнее, чем считать задачу успешной сразу после завершения локального xcodebuild: публикационный контур может отклонить сборку позже.
Маршрутизация задач и модель размещения
Для обычных тестов и сборок выбирайте один из трёх вариантов.
Активный — активный. Оба Mac постоянно принимают задачи. Это оправдано, если нагрузка достаточно стабильна, среда воспроизводима, а очередь умеет учитывать ёмкость и доверие к задаче. Недостаток — больше параллельных обновлений и сложнее расследование различий.
Активный — резервный. Второй узел не принимает обычные задания либо получает только низкорисковые проверки. Его преимущество — более простой контроль production-среды. Недостаток — состояние резерва быстрее устаревает, если автоматическая проверка запускается редко.
Базовый узел плюс эластичный Mac. Постоянная инфраструктура обслуживает ежедневные задачи, а дополнительный Mac включается для миграции, релизного пика или аварийной замены. Это снижает капитальные затраты при неровной загрузке, но требует заранее проверить выдачу доступа и регистрацию runner.
GitHub Runner Groups ограничивают доступ к группам runner, а labels помогают сопоставлять задачу с исполнителем; это следует из документации GitHub по группам runner и меткам self-hosted runner. В Jenkins похожую роль выполняют labels и agents, описанные в документации Jenkins. Для GitLab применяются tags согласно руководству по настройке Runner.
Но ни одна из этих функций сама по себе не проверяет одинаковость Xcode, не изолирует сертификаты и не доказывает, что артефакт можно восстановить. Метка macos-xcode27 — это условие маршрутизации, а не сертификат готовности узла.
Как автоматически распределять задания между двумя Mac
Не привязывайте workflow к именам mac-01 и mac-02. Используйте логические свойства пула:
macos;apple-silicon;xcode-27;production-build;signing-isolated;trusted-runner.
Обычные pull request можно направлять на пул macos, если узел прошёл baseline-проверку. Релизную сборку направляйте на xcode-27 и требуйте дополнительную метку изолированного подписывающего узла. Задания с непроверенными зависимостями не должны иметь доступа к production-пулу.
У правила должен быть явный отказ: если нет узла с нужными атрибутами, задание остаётся в очереди или передаётся оператору, но не «понижается» автоматически до менее доверенного Mac. Ручное переключение должно быть доступно ответственному за релиз и фиксироваться в журнале.
Подпись, секреты и состояние
Разделите данные на восстанавливаемые и невосстанавливаемые.
К восстанавливаемым относятся исходный код, lock-файлы, конфигурация pipeline, логи, кэши и уже опубликованные артефакты. Их можно получать из репозитория, хранилища или системы артефактов. К невосстанавливаемым либо чувствительным активам относятся закрытые ключи, сертификаты, provisioning profiles, токены и сервисные учётные данные.
Как разделить сертификаты между двумя узлами без утечки ключа
Не делайте общий Keychain резервным хранилищем и не копируйте весь профиль пользователя на второй Mac. Для каждого подписывающего контура определите:
- какой job имеет право на подпись;
- какой пользовательский контекст запускает
xcodebuild; - где хранится секрет;
- как секрет выдаётся на время задания;
- кто может отозвать доступ;
- как фиксируется использование;
- как удаляются временные материалы после завершения.
Обычные тестовые узлы должны собирать и тестировать без доступа к production private key. Резервный подписывающий узел может иметь подготовленную, но строго ограниченную процедуру активации. При компрометации ключа задача меняется: это уже не плановое переключение, а немедленное прекращение использования, отзыв сертификата, выпуск нового секрета и проверка всех связанных pipeline.
Такой подход медленнее бездумного копирования, зато ограничивает последствия вредоносного задания или ошибочного скрипта. Подробности о конфиденциальности и обращении с данными при выборе удалённой инфраструктуры стоит сопоставить с материалами SSHMac о приватности.
План восстановления и пошаговая приёмка
Резервный Mac становится частью production только после доказательной проверки. Не подставляйте универсальные значения времени восстановления или допустимой потери данных: их должен утвердить владелец продукта и зафиксировать в корпоративном плане непрерывности.
Выполните процедуру по шагам.
-
Опишите минимальный релизный путь. Укажите commit, тесты, экспорт, подпись и загрузку в App Store Connect. Отдельно отметьте действия, которые можно выполнить вручную при недоступности автоматического контроллера.
-
Составьте карту отказов. Проверьте основной Mac, CI-контроллер, сеть, хранилище артефактов, Xcode, узел подписи и внешние сервисы. Для каждого ресурса назначьте владельца и допустимый способ обхода.
-
Проверьте baseline второго узла. Скрипт должен сравнить macOS, build Xcode 27, SDK, зависимости, настройки проекта и разрешения Keychain. Различие блокирует допуск, пока его причина не подтверждена.
-
Запустите один и тот же commit на обоих Mac. Сравните тесты, логи, артефакты и подпись. Не ограничивайтесь зелёным статусом CI: проверьте фактический архив и его загрузку.
-
Имитируйте отключение основного узла. Удалите его из пула маршрутизации, не меняя код и конфигурацию задания. Зафиксируйте обнаружение отказа, постановку в очередь, выбор резервного runner и получение артефакта.
-
Проверьте production-подпись. Убедитесь, что резервный путь не выдаёт секрет обычному runner и запускается только в разрешённом контексте. Любой обход этого правила означает отрицательный результат приёмки.
-
Проверьте сетевой и внешний сбой. Отдельно рассмотрите недоступность репозитория, артефактного хранилища и App Store Connect. Если система не может завершить публикацию, она должна честно остановиться, а не создать неподтверждённый результат.
-
Верните основной узел. Убедитесь, что незавершённая задача не запускается повторно без проверки идентификатора commit и артефакта. После возврата сравните состояние среды с baseline, иначе обратное переключение может вернуть дрейф.
-
Сформируйте протокол. Запишите время обнаружения, переключения, сборки, подписи, загрузки и восстановления; приложите логи, идентификатор задания и решение ответственного лица.
Итог должен быть одним из трёх: «пройдено», «пройдено с условиями» или «отклонено». Условный результат требует конкретного владельца и срока исправления, а не устного обещания. Если не подтверждены подпись, внешний доступ или отсутствие повторной публикации, второй узел нельзя объявлять готовым.
Стоимость и эксплуатационная модель
Сравнивайте не цену второй машины, а полный цикл владения:
- закупка или аренда Mac;
- доставка, размещение, питание и сетевое подключение;
- запас ёмкости под релизные пики;
- обновление macOS и Xcode;
- восстановление после повреждённой среды;
- хранение артефактов и логов;
- регулярные тесты переключения;
- время инженеров на обслуживание;
- стоимость задержанного релиза.
Фиксированная нагрузка и постоянная потребность в подписи обычно оправдывают долгосрочную пару собственных узлов, если компания готова самостоятельно поддерживать оборудование и физический доступ. Неровная нагрузка, миграция на Xcode 27 и необходимость быстро проверить резервный путь чаще подходят для базовой машины плюс удалённый Mac по подписке. Условия аренды и доступные варианты можно сверить на странице аренды Mac mini в SSHMac, но коммерческие параметры нужно сопоставлять с вашей политикой безопасности, регионами и требованиями к доступу.
Удалённый Mac не заменяет независимое хранилище, резервирование CI-контроллера или процедуру ротации ключей. Его роль — дать физически отдельный узел для проверки сборки, временно принять задания или пережить пик, пока команда решает вопрос постоянной инфраструктуры.
Для закупочного решения зафиксируйте четыре пункта: кто разрешает переключение, какой лог считается доказательством, при какой очереди добавляется ёмкость и когда временный узел отключается. Без этих условий эластичная инфраструктура легко превращается в постоянную, но плохо контролируемую статью расходов.
Итоговое решение
Если у вас стабильная ежедневная нагрузка, создавайте два baseline-совместимых Mac-узла и распределяйте между ними обычные сборки. Production-подпись при этом должна оставаться в отдельном доверенном контуре с заранее проверенным резервом. Если нагрузка скачет или команда только переносит пайплайн на Xcode 27, не спешите покупать постоянное оборудование: сначала добавьте изолированный удалённый Mac, выполните полную процедуру переключения — сборка, подпись, загрузка и возврат — и примите решение по журналу.
Единственный локальный Mac сохраняет риск простоя при обслуживании, ограничивает релизную ёмкость и требует ручного восстановления после повреждения среды. Покупка второго устройства снижает риск отказа хоста, но добавляет расходы на простой, обновление, физическое размещение и регулярную проверку готовности. SSHMac в таком сценарии может быть практичнее как временный резервный узел или мощность для релизного пика: вы проверяете реальный pipeline до долгосрочной закупки, не выдавая удалённому Mac роль универсальной замены всей платформы.
Начните с инвентаризации общих точек отказа и одной контролируемой тренировки переключения. Если журнал подтверждает среду, подпись и возврат без дрейфа, тогда уже выбирайте постоянную пару Mac или продолжайте аренду как управляемую эластичную часть корпоративного CI/CD.