2026: React Native / Expo — оставаться на EAS?
Очереди, нативные зависимости и self-hosted на выделенном удалённом Mac

Если вам близок подход «как к VPS» к вычислительной мощности, а в React Native / Expo вы упираетесь в «очередь EAS, нативные модули и форму учётных данных», эта статья сводит управляемую сборку и выделенную плоскость macOS в одной таблице: сначала разбор болевых точек, затем матрица решений и шестишаговый чек-лист, в конце — ритм самостоятельно размещаемой сборки с опорой на аудит. После прочтения будет ясно, когда рационально остаться на EAS, а когда перенести iOS-сборки на арендованный удалённый Mac как отдельный узел.

01

Шесть типовых болевых точек у команд RN/Expo в 2026 на «управляемом EAS»

Expo Application Services (EAS) хорошо упаковывают сертификаты, загрузку и облачные сборки и подходят для стандартного пути. Когда в репозитории много нативных патчей, приватных Pod и нужно вписать логи сборок и audit trail команд в пакет соответствия, непрозрачная очередь и границы образа управляемого пула начинают мешать. Ниже шесть кластеров, обобщённых по реальным сессиям разбора, чтобы оценить, не нужен ли вам второй, «с доступом по SSH» контур сборки.

  1. 01

    Семантика очереди неочевидна: в пик воркфлоу может ожидать в очереди десятки минут; если релизное окно жёстко зафиксировано с бизнесом, эта неопределённость перерастает в риск инцидента. У пула нельзя зафиксировать «максимальную конкуренцию» в духе внутреннего SLA, в отличие от выделенного узла.

  2. 02

    Длинная нативная цепочка: react-native-config, Firebase, карты и Bluetooth при кастомных Podspec и прекомпиляционных сценариях снижают долю попаданий в кэш образа, время одной сборки сильно плавает; при отладке нет «шелла на хосте» с полным выводом xcodebuild -showBuildSettings.

  3. 03

    Расхождение моделей подписи и учётных данных: при одновременном EAS-управляемом подписании и внутреннем match / собственном CA «локально Archive проходит, в облаке изредка падает»; часто виноваты контекст связки ключей и сочетание CODE_SIGN_IDENTITY, не полностью воспроизводимое в чужом образе.

  4. 04

    Неконтролируемый уровень диска и DerivedData: в крупном monorepo на общем воркере чаще срабатывают агрессивные чистки, сбивая «тёплый» кэш; командам с частыми UI-тестами и Archive это даёт длинные хвосты по времени.

  5. 05

    Рассинхрон с вашей схемой меток в CI: для бэкенда и Web в GitHub Actions уже заданы labels, лимиты конкуренции и self-hosted runner, а iOS живёт в другом оркестраторе — операционная модель и дежурства распадаются на две ветки.

  6. 06

    Недостаточно полей для аудита: в финансах, медицине или регулируемом экспорте нередко требуют «кто, с какого IP, на каком билд-хосте какие команды запускал»; если с управляемой стороны нельзя выгрузить сырые SSH/сеансы в формат, согласованный с внутренним SOC2, выделенный узел закрывает цепочку доказательств.

Если срабатывают два и более пункта, разумно читать дальше сравнительные таблицы и шаги; если сборки редкие, а нативный слой тонкий, на первом этапе стоит выжать EAS, не раздувая собственный контур. Подробности «как вешать runner на выделенный узел» вынесены в материал о self-hosted runner в GitHub Actions, здесь — разделение зон в терминах RN/Expo.

02

EAS Build и «выделенный удалённый Mac + self-hosted iOS»: какой тип нагрузки куда

Сводить варианты в одной таблице — не ради критики EAS, а чтобы в ревью говорить на одном языке об очереди, образе, подписи и аудите. Таблица исходит из того, что команда уже пользуется profile в eas.json и обладает базовыми навыками сопровождения macOS.

ИзмерениеEAS Build (управляемый)Self-hosted на выделенном удалённом Mac
Скорость выдачи (холодный старт)Высокая, без закупки железа и установки ОССредняя, нужна первичная настройка SSH, «отпечатка» Ruby/Node и регистрация runner
Контроль очереди и конкуренцииЗависит от общего пула, пиковая задержка слабо предсказуемаЭксклюзивные CPU/диск, фиксированные верхние границы конкуренции и окна уборки
Сложность нативного стекаХорошо для типового сценария ExpoУместно при глубоком нативе, кастомных Pod, пре-скриптах и цепочке локальных патчей
Политика подписи и сертификатовТесно с учётными данными EASМожно выровнять с match, внутренним KMS и разграничением связок ключей по средам
Логи и аудитПлатформенные логи, детализация ограничена продуктомПолный вывод xcodebuild и shell-сессий для внутреннего контроля
Операционная нагрузкаНизкая, ближе к «CI как сервису»Средняя и выше, ближе к «как к кластеру VPS»

«Управляемая сборка решает задачу от нуля к единице; выделенный узел — от единицы к масштабу: предсказуемость и проверяемость.»

Типичный компромисс: ежедневные пакетные и PR-контуры — на EAS, а Release Archive, матрицу UI-тестов и итерации с тяжёлым нативом — на выделенный удалённый Mac. Так «дорогие» человеко-часы удерживаются в среде с контролируемыми параметрами, оставляя силам интеграции удобный управляемый путь.

03

Матрица: когда оставаться на EAS, когда вводить выделенную плоскость macOS

Матрица ниже по сигналам «масштаб команды × глубина нативного слоя × сила требований к комплаенсу» даёт практичные ориентиры. Она не заменяет вашу ёмкостную смету, но ускоряет согласование приоритетов в архитектурной сессии.

СигналОсновной упор на EASПодключать выделенный удалённый Mac
Нативные зависимостиНемного community-модулей, без кастомных PodПриватные Pod, бинарные проприетарные SDK или нестандартные флаги компиляции
Релизный ритмЕженедельные / двухнедельные циклы, допустимы пики очередиЕжедневные релизы или жёсткие временные боксы, нужны фиксированные конкуренция и окна
КомплаенсНет требований к полевому аудитуНужен аудит на уровне SSH/команды, фиксированный egress или сегментация VPC
Текущий CIiOS-конвейер обособлен от бэкендаХотите общие labels и кэш-политику с GitHub Actions / GitLab для iOS job
json
// Фрагмент eas.json: развести «управляемую» сборку и внешний self-hosted job по profile
{
  "build": {
    "preview": { "distribution": "internal", "channel": "preview" },
    "release-selfhosted": {
      "extends": "production",
      "env": { "EXPO_USE_FAST_RESOLVER": "1" },
      "ios": { "image": "latest" }
    }
  },
  "submit": { "production": {} }
}
warning

Внимание: при смешении в одной ветке управляемого и self-hosted путей обязательно в README укажите, какой profile к какой модели учётных данных ведёт; иначе новые участники застрянут между связкой ключей и EXPO_TOKEN.

Помимо матрицы: «собирается» не равно «воспроизводится». Обновления образа на стороне провайдера происходят в фоне; если в репозитории не зафиксированы мажор Xcode и младший Node, нативный слой React Native после «незаметного» апгрейда может валиться пакетно. Плюс выделенного узла — закрепить xcode-select и Ruby Bundler как версию ядра и записать отпечаток в договор CI.

04

Шесть шагов, чтобы встроить «выделенный удалённый Mac» в цепочку поставки RN/Expo (с приоритетом SSH)

Шаги исходят из того, что npx expo prebuild у вас уже выдаёт iOS-проект, а на выделенном хосте нужны xcodebuild или Fastlane. Намеренно в духе администрирования VPS: учётка, ключи, уровень диска и отдача логов в одной связке.

  1. 01

    Заморозить отпечаток тулчейна: на удалённом Mac зафиксировать xcodebuild -version, node -v, ruby -v, pod --version в BUILD_ENV.lock репозитория; любое обновление — через PR, без «чьего-то» SSH-апгрейда в обход.

  2. 02

    Отдельный неинтерактивный пользователь для CI: не гоняйте пакетные задачи в сессии личного Apple ID; для runner или SSH job выделите пользователя и изоляцию связки ключей, в той же плоскости, что в гайде по воспроизводимым сборкам.

  3. 03

    Разнести пути DerivedData и Pods: по репозиторию или ветке, например ~/DerivedData/$REPO/$BRANCH и ~/PodsCache/$REPO; стратегию уборки задавайте по cron, а не надеясь на агрессивную уборку ОС.

  4. 04

    Вернуть iOS job в основной CI: self-hosted labels в GitHub Actions / GitLab на выделенный Mac, с теми же воротами согласования и конкуренции, что и Android; VNC — только в контролируемом окне отладки, а не «всегда включённый десктоп».

  5. 05

    Артефакты и логи наружу: в контролируемое object storage или внутренний реестр — .ipa, dSYM и сырые логи xcodebuild; при требованиях регулятора — дополнительно запись сеанса до уровня команд для последующей экспертизы.

  6. 06

    Двухнедельный контрольный эксперимент: пять характерных веток, параллельно измеряйте P50/P95 длительности и типы сбоев на EAS и на выделенном хосте; если при тяжёлом нативе выделенный хост стабильнее и дисперсия очереди меньше, переносите туда трафик Release.

info

Заметка: если ещё оцениваете регион и ёмкость диска, сначала сверьтесь с страницей тарифов аренды и вынесите в спецификацию ось «конкуренция × уровень диска × регион», затем сопоставьте с чек-листом выше.

05

Три жёсткие формулировки для пакета ревью (с ориентирами, на которые можно ссылаться)

  • Разброс длительности сборки (P95 / P50): в типичных в 2026 выборках RN monorepo на общем пуле при «холодном кэше + нативной цепи» P95 нередко в 2,5–4 раза выше P50; на узле с NVMe и контролем диска отношение сжать до ~1,4–1,8 проще, потому что уровень диска и конкуренция описаны вами в договоре. Агрегат по сопоставимым пилотам, не один лабораторный бенчмарк.
  • Линия диска: при двух крупных Xcode, нескольких рантаймах симуляторов и зависимостях RN разумно закладывать не менее 600 ГБ свободного как годовую базу; при падении ниже ~120 ГБ — автоматическая уборка или второй узел, иначе xcodebuild на этапе линковки падает «случайно».
  • Контракт по конкуренции и очереди: формализованное «максимум N параллельных job на выделенной машине в релизном окне» (например, в окне релиза один Archive) снижает риск сильнее, чем бесконечная докупка «минут» на управляемой стороне: узкое место часто в подписантах и согласованиях, а не в CPU.

Держать iOS целиком на общем пуле краткосрочно дешевле по людям; но когда нативные зависимости, требуемая детализация аудита и единая оркестрация с GitHub Actions / GitLab превращаются в жёсткие условия, «чёрная» очередь и незакреплённый образ накапливают дисперсию. С другой стороны, кластер Mac без дисциплины диска и «отпечатков» деградирует в отдельный снежный ком.

В сухом остатке командам поставки RN/Expo, которым нужны предсказуемая 24/7 очередь, проверяемые сеансы команд и единая схема runner-меток, тяжёлая нагрузка ближе к выделенной плоскости macOS, а EAS остаётся на лёгкую интеграцию и внешнюю коммуникацию. Для сценариев, где среда исполнения должна быть договариваемой нодой, с сокращением дисперсии очереди и обслуживанием iOS CI/CD и длительной автоматизации, аренда Mac Mini в облаке NodeMini часто оказывается рациональнее.

FAQ

Частые вопросы

Когда iOS-контур должен вести себя как увеличиваемый узел: фиксированные диск и конкуренция, экспортируемые логи на уровне команд или нативная цепь не вписывается в образ — выделенный удалённый Mac уместен. Сначала пилот по странице тарифов, затем решение о полном переносе Release job.

Да, поэтому жёстко разводите profile и границы связки ключей: на EAS — только EAS-управляемое подписание, на self-hosted — match или корпоративный KMS; критерии переключения в README. Дополнительно — справочный центр, разделы про SSH и учётные записи.

В гайде по runner — метки, кэш и очереди; здесь — разграничение EAS и выделенной плоскости в терминах RN/Expo. Если runner уже на удалённом Mac, шестишаговый чек-лист выше можно трактовать как расширение критериев приёмки.