Разработка в разных регионах · эстафета сборок

Один Mac —
эстафета по часовым поясам

Коллеги в Азиатско-Тихоокеанском регионе отправляют код, а команда в Северной Америке собирает релиз. Среда сборки остается в дата-центре и не зависит от того, чей компьютер сейчас включен.

Весь компьютер арендует один клиент — это не виртуальная машина. Две конфигурации Apple M4, 5 узлов, доступность 365 дней в году.

От $19.2 в день. Электропитание, сеть и охлаждение обеспечивает дата-центр; команда настраивает пайплайны проекта, очереди сборки и права на выпуск.

Непрерывная интеграция

Задачи в очереди — сборка продолжается ночью

Перенесите компьютер для сборки Xcode из офиса в дата-центр. Каждый push запускает задачу: больше не нужно полагаться на компьютер коллеги, оставленный включенным и подключенным к питанию.

Начните с воспроизводимого пайплайна

Зарегистрируйте на компьютере собственный macOS runner и настройте запуск веток, тестовых целей и пути к артефактам по правилам репозитория. Сначала убедитесь, что сборка из командной строки проходит успешно, затем включите автоматический запуск — так будет проще отделить проблемы среды от ошибок настройки CI.

Для последовательной сборки одного приложения подойдет Push M4 S: M4 / 16GB / 256GB SSD. Сохраняйте кэш зависимостей и DerivedData, чтобы следующие задачи использовали те же каталоги; не запускайте несколько задач, записывающих одни и те же файлы сборки.

Доступность 365 дней в году снимает зависимость от размещения компьютера в офисе и перебоев с электричеством, но не обеспечивает автоматическое восстановление задач после сбоев. Автозапуск runner, повторные попытки, очистку диска и уведомления о логах нужно настроить в пайплайне команды.

Сначала проверьте archive, затем подключайте runner

В примере используются App.xcworkspace и схема App из каталога проекта. Перед запуском замените их фактическими именами.

xcodebuild -version

xcodebuild \
  -workspace App.xcworkspace \
  -scheme App \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  -derivedDataPath build/DerivedData \
  -archivePath build/App.xcarchive \
  archive

Заранее подготовьте настройки подписи. Эта команда создает archive, но не выполняет экспорт или загрузку.

Работа в разных часовых поясах

Смены по часовым поясам — без потери контекста

Команда в Азиатско-Тихоокеанском регионе работает днем, а узел на востоке США может принять задачи на сборку и выпуск в дневное время в Северной Америке. Выбирайте узел по расположению основных пользователей, а сборки передавайте через очередь.

Перед запуском сохраните входные данные

Запишите ветку, commit, схему, версию Xcode и параметры сборки. Следующий исполнитель продолжит с того же коммита, не пытаясь угадать по переписке, «какую версию запускали».

Данные для передачи: хеш коммита + идентификатор задачи.

Ограничьте параллельное выполнение

Выделенный компьютер не означает неограниченный параллелизм. Настройте очередь или блокировку для одного Mac; подпись и экспорт выполняйте последовательно. Для разных проектов используйте отдельные рабочие каталоги и ключи кэша.

Данные для передачи: состояние очереди + путь к логам.

Принимайте задачу с проверкой результатов

Сначала проверьте результаты тестов, archive и логи экспорта, затем запустите согласование выпуска. Если задача завершилась с ошибкой, сохраните текущее состояние и логи — не очищайте кэш и не запускайте сборку заново без проверки.

Данные для передачи: расположение артефактов + результат согласования.

Учитывайте отдельно подключение и выполнение задач

Доступны узлы в Сингапуре, Токио, Сеуле, Гонконге и на востоке США. Для работы в VNC в первую очередь учитывайте расположение пользователя; для автоматической сборки — также сетевой маршрут до репозитория и источников зависимостей. Часовой пояс помогает планировать работу, но не гарантирует низкую задержку. Если команды часто работают между континентами, можно настроить отдельные компьютеры для каждого региона и унифицировать метки runner.

Подпись и выпуск

Весь процесс выпуска — на одном компьютере

Создавайте archive для публикации в App Store, подписывайте и загружайте приложение в неизменной среде сборки. Сведите к минимуму перенос среды и не копируйте сертификаты на компьютеры сотрудников.

  1. 01

    Зафиксируйте цепочку инструментов

    Укажите путь к Xcode для ветки выпуска, зафиксируйте SDK и lock-файлы зависимостей. Не полагайтесь на версию, выбранную в прошлый раз в графическом интерфейсе; записывайте фактически использованную цепочку инструментов в лог сборки.

  2. 02

    Храните сертификаты централизованно

    Храните сертификаты и профили подготовки на выделенном компьютере для выпуска, а доступ к связке ключей ограничьте минимально необходимыми правами. Передавайте пароли через защищенные переменные CI — не записывайте их в репозиторий, вывод команд или общедоступные логи.

  3. 03

    Разделите архивирование и экспорт

    Сначала сохраните xcarchive, затем экспортируйте приложение с помощью проверенной командой конфигурации ExportOptions. Настройте авторизацию и согласование загрузки отдельно, чтобы различать ошибки компиляции, подписи и загрузки.

  4. 04

    Сохраняйте подтверждение выпуска

    Свяжите номер версии, хеш коммита, лог сборки и артефакты. Используйте сертификаты только в необходимых местах и храните их зашифрованные резервные копии в безопасном месте под контролем команды — это поможет избежать потери единственной копии.

Кроссплатформенные проекты

Сборка нескольких целей: оставьте запас памяти

Для сборки iOS-приложений на Flutter и React Native по-прежнему нужны инструменты macOS. Храните нативные зависимости, Pods и кэш Xcode на выделенном компьютере, чтобы не настраивать среду заново перед каждым запуском.

Push M4 S · последовательная сборка

M4 / 16GB / 256GB SSD

Подходит для повседневного CI одного приложения, одной очереди выпуска и первой проверки стабильности сборок кроссплатформенного проекта. Сборка, симуляторы и другие процессы используют общую память компьютера: сначала запускайте задачи последовательно и увеличивайте их число, оценив пиковую нагрузку.

Сохраняйте lock-файлы зависимостей и задавайте отдельные ключи кэша для разных веток. Переносите старые артефакты в собственное хранилище команды, чтобы архивы не занимали весь локальный диск.

Push M4 L · задачи с несколькими целями

M4 / 24GB / 512GB SSD

Подходит для archive с несколькими целями, смешанных сборок Flutter / React Native и проектов, которым нужно хранить больше зависимостей и версий инструментов. 24GB дают больше запаса памяти для параллельных задач, но допустимое число одновременных запусков нужно проверять на реальном проекте.

Отдельно фиксируйте длительность сборки, нагрузку на память и занятое место на диске. Если проблема связана с загрузкой через сеть между регионами или ожиданием блокировки подписи, увеличение памяти напрямую не поможет — сначала настройте кэш и очередь.

Если одновременно растут объемы данных нескольких версий Xcode, кэша зависимостей и archive, рассмотрите дополнительный SSD на +1TB или +2TB. Расширение увеличивает объем хранилища, но не объем унифицированной памяти. Сначала выясните, что именно занимает место, а затем выбирайте объем.

Эксперименты на Apple Silicon

Запускайте небольшие задачи инференса в свободное время

Один и тот же Mac в облаке можно использовать для инференса локальных моделей, проверки скриптов и небольших тестов. Сначала убедитесь, что модель помещается в унифицированную память, затем планируйте запуск между задачами выпуска.

Учитывайте не только размер файла модели

В унифицированной памяти должно хватить места для macOS, фреймворка инференса, кэша контекста и других процессов. Размер файла модели не равен объему памяти, необходимому во время работы. Начните с короткого ввода и постепенно увеличивайте контекст и размер пакета.

Записывайте: версию модели, способ квантования, пиковое потребление памяти.

Указывайте условия теста в результатах

Зафиксируйте версии фреймворка, входные данные и параметры генерации, затем сравнивайте время выполнения и результаты. Выбирайте между 16GB и 24GB исходя из стабильной работы нужной задачи, а не из предположений об универсальном размере модели или скорости.

Записывайте: длину ввода, параметры запуска, время выполнения.

Не запускайте эксперименты во время подписи релиза

Инференс и компиляция в Xcode конкурируют за вычислительные ресурсы и память. Во время выпуска приостанавливайте очередь экспериментов; используйте для скриптов отдельный каталог и права доступа, не открывайте им доступ к связке ключей для выпуска. Сохраняйте результаты длительных задач.

Записывайте: приоритет задачи, условие остановки, путь к результатам.

Подходит для задач проверки, которым нужны macOS и Apple Silicon, но небольшие эксперименты не следует приравнивать к масштабному обучению моделей. Начните с аренды на день, проверьте свой рабочий процесс и затем решите, как использовать компьютер дальше.

Правила передачи задач в команде

Превратите рабочие потребности в четкие правила

Ниже приведены примеры формулировок для двух ролей. Они иллюстрируют организацию задач и не являются подтвержденными отзывами клиентов или результатами измерений производительности подключения.

«Мы запускаем Fastlane на одном выделенном компьютере. Кто бы ни был на дежурстве, он сначала смотрит один и тот же отчет о сборке — больше не нужно ждать, пока кто-то включит компьютер».
Правило работы: хранить скрипты выпуска в репозитории, связывать идентификатор задачи с archive и логом экспорта.
Руководитель мобильной разработки · пример сценария
«Сначала я проверяю удаленный рабочий стол из сети тестировщика, а затем выбираю узел. Автотесты идут через очередь, а когда нужна проверка человеком, я подключаюсь к рабочему столу».
Правило работы: проверять подключение из фактической сети пользователя, отделять ручную проверку от пакетного тестирования.
Руководитель QA · пример сценария

Выберите конфигурацию под свои задачи

Для последовательной сборки одного приложения начните с 16GB; для нескольких целей и смешанных сборок рассмотрите 24GB. Выберите основной рабочий узел и запустите на нем первый пайплайн.

Выделенный физический Mac mini, аренда от $19.2 в день. Фактическая доступность отображается в консоли в реальном времени.