01

Короткий вывод по срокам и действие на этой неделе

Факт на текущий момент: Apple уже выпустила Xcode 26, а его требования к инструментам и платформе опубликованы в официальных заметках к выпуску. Это означает, что для сборки iOS в Bazel 9 нужен не просто исполнитель команд, а согласованный узел macOS с подходящим Xcode и Apple SDK. Подтверждение доступно в официальных заметках Apple о Xcode 26.

Решение: полный цикл — компиляция Apple-целей, линковка, Simulator, подпись, архивирование и экспорт — следует оставлять на реальном Mac. Linux можно использовать для анализа, генерации, проверок и тестов без Apple-зависимостей. На этой неделе разумно собрать матрицу action, запустить чистую сборку на изолированном удалённом Mac и только после этого решать, достаточно ли одного узла или требуется гибридный CI.

Эта статья предназначена для инженеров сборочной платформы, которые подключают Bazel 9 к iOS-проекту и распределяют задачи между Linux и macOS. Она также пригодится DevOps-командам с Linux-кластером и техническим руководителям, оценивающим расширение Apple-платформы.

Дата последней проверки — 29 августа 2026 года. Сведения сверены с публикацией о модели выпусков Bazel, объявлением Bazel 9, документацией rules и материалами Apple. Конкретные сочетания минорных версий необходимо перепроверять перед каждым обновлением toolchain.

02

Граница инструментов: Bazel не заменяет Apple toolchain

Bazel отвечает за описание графа сборки, анализ зависимостей, выбор платформы, запуск action и работу с кэшем. Он не поставляет Apple SDK, Simulator, signing tools или содержимое Xcode. Поэтому успешный запуск команды bazel build на Linux ещё не доказывает, что приложение можно архивировать и передать в App Store.

Роли компонентов нужно разделять:

  • Bazel 9 планирует и выполняет действия, разрешает платформы и toolchain;
  • rules_apple описывает Apple-цели, ресурсы, bundle, архивирование и связанные правила;
  • rules_swift связывает Swift-компиляцию с графом Bazel;
  • Xcode предоставляет Apple SDK, clang, Swift toolchain, xcodebuild, Simulator и инструменты подписи;
  • macOS является операционной средой, в которой эти Apple-компоненты должны согласованно работать.

Поддержка Bazel 9 со стороны правил не превращает Linux в полноценную среду iOS-разработки. Перед миграцией нужно открыть текущие релизы rules_apple и документацию rules_swift, после чего зафиксировать конкретную комбинацию версий. Формулировка «поддерживается Bazel 9» не всегда отвечает на вопрос о каждом минорном выпуске Xcode 26, SDK и используемых правилах.

В MODULE.bazel должны быть явно видны зависимости и версии. Для Bazel 9 это особенно важно: старый подход через WORKSPACE больше нельзя считать единственной точкой входа для зависимостей. Если проект всё ещё полагается на неявную загрузку из старого файла, переход необходимо проверять отдельно, а не считать механической заменой версии Bazel.

Быстрый начальный аудит может выглядеть так:

bazel info release
bazel query @rules_apple//...
xcodebuild -version
xcrun --sdk iphoneos --show-sdk-path
xcrun simctl list devices available

Пример ожидаемого принципа проверки, а не фиксированного вывода:

Bazel release: 9.x
Xcode: 26.x
iPhoneOS SDK path: /Applications/Xcode.app/...
Available Simulators: ...

Число 9.x или 26.x здесь является шаблоном. В рабочем отчёте должны присутствовать реальные значения, дата проверки и ссылка на зафиксированный образ узла.

03

Метрика совместимости определяет, продолжать ли миграцию

Совместимость нужно оценивать не по тому, завершается ли первая команда без ошибки, а по четырём последовательным результатам:

  1. Bazel разрешает нужные платформы и toolchain.
  2. Apple-цели компилируются с ожидаемым SDK.
  3. Simulator-тесты запускаются без ручного вмешательства.
  4. Архив подписывается и экспортируется в пригодный для доставки формат.

Если выполнен только первый или второй пункт, перед командой не полноценный iOS CI, а промежуточный этап сборки. Официальная документация Bazel описывает платформы и toolchain resolution, однако конкретные Apple-ограничения всё равно задаются Xcode и SDK.

В проекте стоит зафиксировать минимум следующие поля:

Объект Что фиксировать Почему это влияет на решение
Bazel Полный выпуск и способ запуска Меняется поведение анализа и загрузки зависимостей
rules_apple Версия или commit Определяет доступные Apple-правила
rules_swift Версия или commit Влияет на Swift toolchain и переходы
Xcode Полный номер и путь установки Определяет SDK, Simulator и signing tools
SDK Путь и тип SDK Ошибка здесь превращает сборку в непереносимую
macOS Версия образа узла Ограничивает совместимость Xcode
MODULE.bazel Зафиксированные зависимости Убирает скрытый источник расхождений

Если нужная комбинация не подтверждена текущими release notes, есть три безопасных решения: оставить существующую связку, обновить правила вместе с Bazel и Xcode в отдельной ветке или временно остановить миграцию. Сообщение из сообщества можно использовать как сигнал для теста, но не как доказательство совместимости.

04

Разделение action между Linux и macOS

Распределять работу следует по фактическим входам action, а не по названию скрипта. Например, этап с именем build-ios может включать генерацию исходников на Linux, компиляцию на macOS и последующую упаковку. Обратная ситуация также возможна, если универсальный скрипт случайно вызывает Apple-инструмент.

К Linux обычно можно отнести:

  • форматирование и статический анализ исходников;
  • проверку зависимостей и содержимого MODULE.bazel;
  • генерацию файлов, не использующую Apple SDK;
  • тесты чистой бизнес-логики;
  • проверку конфигурации и публикацию логов;
  • подготовку входных данных для Apple-specific action.

На macOS следует направлять:

  • компиляцию и линковку iOS-целей;
  • действия, использующие iphoneos или iphonesimulator SDK;
  • запуск Simulator;
  • обработку bundle и ресурсов Apple-приложения;
  • code signing и работу с provisioning profile;
  • создание архива и экспорт IPA либо другого релизного артефакта.

Здесь важно не смешивать три разных понятия:

  • удалённый кэш хранит результаты action;
  • удалённое выполнение запускает action на управляемом исполнителе;
  • удалённый Mac предоставляет саму macOS-среду, Xcode и Apple SDK.

Документация Bazel по правилам удалённого выполнения не означает, что любой удалённый исполнитель может запускать Apple-действия. У него должны быть нужная операционная система, toolchain, SDK, разрешения и безопасный доступ к секретам.

Проверять реальный маршрут следует подробным журналом:

bazel build \
  --announce_rc \
  --subcommands=pretty_print \
  --verbose_failures \
  //path/to:ios_app

В отчёте нужно сохранить action mnemonic, платформенные ограничения, команду, executor и причину промаха кэша. Если система CI показывает только зелёный статус, этого недостаточно: успешный результат мог быть восстановлен из кэша и не подтвердить работу текущего Mac-узла.

05

Воспроизводимость строится вокруг явных зависимостей

Сборка считается воспроизводимой не тогда, когда один разработчик дважды получил зелёный статус, а когда чистый клон на новом исполнителе даёт сопоставимый набор результатов. Для Bazel 9 нужно отдельно проверить:

  • загрузку модулей из MODULE.bazel;
  • отсутствие зависимости от старого WORKSPACE;
  • версии rules и их транзитивных зависимостей;
  • путь к Xcode и выбранный SDK;
  • переменные PATH, DEVELOPER_DIR и аналогичные настройки;
  • наличие локальных скриптов на диске хоста;
  • инструменты, которые вызываются, но не объявлены как inputs;
  • доступ к сертификатам, связке ключей и provisioning profile.

Частая ошибка — считать локально установленный бинарник частью Bazel-графа. На одном Mac он находится в PATH, на другом отсутствует; результатом становится неочевидный сбой только после замены узла. Аналогично опасны абсолютные пути к рабочему столу, файлам пользователя и каталогам кэша.

Минимальный эксперимент должен включать четыре запуска:

  1. сборка после чистого клонирования;
  2. повторная сборка на том же узле;
  3. сборка после очистки локального кэша;
  4. сборка на заменяемом Mac-узле с тем же описанием среды.

Сравнивать нужно не только код возврата. В журнале фиксируются версии, action, входные файлы, cache hit или miss, итоговый bundle, тестовые результаты и причина любого отличия. Для релизного контура отдельно сохраняются checksum архива и сведения о подписи.

06

Кэш и время очереди показывают реальное узкое место

Смешанная архитектура не становится эффективнее автоматически. Она может ускорить поток, если Linux освобождает Mac от независимых подготовительных задач, но может добавить задержку из-за очереди, передачи больших inputs и холодного кэша.

Решение следует принимать по наблюдаемым метрикам:

  • доля cache hit отдельно для Linux и macOS;
  • время ожидания Mac-исполнителя;
  • длительность компиляции, линковки, Simulator и подписи;
  • объём переданных входов и выходов;
  • число повторных запусков после сбоев;
  • время восстановления узла после перезапуска;
  • частота блокировки очереди Apple-задачами.

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

Удалённый кэш полезен только при корректной идентичности среды. Если результаты Xcode 26, SDK или signing action смешиваются без контроля, высокий cache hit может скрывать неправильный артефакт. Для подписи кэш и секреты должны рассматриваться раздельно: сертификат не должен попадать в общий архив входов или выходов.

07

Подпись и Simulator формируют границу поставки

Без подписи можно проверить часть компиляции, но нельзя доказать работоспособность релизной цепочки. В production-проверку следует включить:

  • сборку под устройство;
  • Simulator-тесты;
  • создание архива;
  • проверку подписи;
  • экспорт артефакта;
  • проверку bundle identifier и provisioning profile;
  • сохранение диагностических логов;
  • повтор после перезапуска узла.

Apple описывает связь сертификатов и provisioning profile в технической заметке о code signing. Из этого следует практическое правило: ключевая связка, профиль и пароль не должны жить в исходном репозитории или в общей файловой системе кэша.

Для безнадзорной сессии нужно заранее решить, каким способом CI получает секреты. Ручной вход в графическую сессию, всплывающее окно Keychain или подтверждение на рабочем столе делают узел непригодным для устойчивого CI. Ключи следует выдавать короткоживущему заданию с минимальным доступом, а после завершения проверять очистку временных файлов.

В рабочей диагностике полезен отдельный блок:

xcodebuild -version
security find-identity -v -p codesigning
xcrun simctl list devices available
bazel test --test_output=errors //path/to:ios_tests

Команда security не должна выводить секреты в общий лог. В систему отчётности передаются только факт наличия подходящей identity, тип подписи и результат проверки.

08

Три архитектуры и условия выбора

Таблица ниже предназначена для первичного выбора, а не для замены нагрузочного теста.

Архитектура Linux-задачи Apple-задачи Когда выбирать Главный риск
Один удалённый Mac Минимальные или отсутствуют Весь iOS-граф Небольшая команда, один проект, нужен быстрый замкнутый контур Очередь и единая точка отказа
Linux плюс удалённый Mac Анализ, генерация, независимые тесты SDK, Simulator, подпись, архив Средняя и крупная команда с существующим Linux CI Ошибочная маршрутизация или рассинхрон среды
Только Linux Неплатформенные проверки Не выполняются полноценно Только подготовительный этап или не-Apple-проект Нет доказательства поставки iOS
Несколько Mac-узлов Подготовка и диспетчеризация Параллельные Apple-задачи Очередь и время ожидания подтверждённо ограничивают выпуск Рост затрат и сложность одинаковых образов

Небольшой команде обычно выгоднее сначала использовать один изолированный удалённый Mac, пройти полный путь от чистого клона до подписанного архива и собрать журнал. Средней или крупной команде рациональнее оставить Linux для независимых действий, а Apple-часть направить на Mac через платформенные ограничения. Переход к нескольким узлам оправдан только после измерения очереди и повторных запусков.

Подробности подключения и доступные варианты среды можно сверить в описании удалённого Mac от NodeMini. Это не заменяет техническую приёмку, но помогает разделить вопрос доступа к реальному Mac и вопрос корректной конфигурации Bazel.

09

Приёмка узла до включения в постоянный CI

Перед регистрацией узла в общей очереди полезно оформить протокол с конкретными результатами. В нём не должно быть формулировки «сборка работает» без указания действия, платформы и входной среды.

Область проверки Тест Доказательство прохождения Решение при сбое
Совместимость Сборка минимального iOS-проекта Версии Bazel, rules, Xcode, SDK в логе Зафиксировать другую комбинацию
Маршрутизация Подробный action log Исполнитель и platform constraint Исправить toolchain или правило
Чистая сборка Удалить локальный кэш и повторить Сопоставимые выходы и ошибки Найти скрытый input
Simulator Запустить тесты без GUI Отчёт тестов и код возврата Проверить runtime и безнадзорный режим
Подпись Архив и экспорт Архив, identity, profile, checksum Пересобрать secret flow
Восстановление Перезапуск и потеря соединения Автоматическое продолжение либо чистый retry Устранить ручную зависимость
Замена узла Новый Mac с тем же образом Одинаковые action и toolchain Запретить локальную настройку

Дополнительно стоит протестировать смену Xcode 26 на зафиксированную альтернативу только в изолированной очереди. Нельзя менять toolchain внутри общего кэша без отдельного пространства ключей. Иначе старые результаты будут выглядеть пригодными, хотя были созданы другим SDK.

Для удалённого доступа применяется тот же принцип: SSH, VNC и веб-консоль решают задачу управления хостом, но не задачу автоматизации сборки. В CI должен использоваться исполнитель, который стартует без ручного открытия рабочего стола. Инструкции по восстановлению доступа и диагностике среды находятся в справочном центре NodeMini.

10

Три рабочих таблицы для итогового решения

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

Тип действия Базовый узел Условие переноса Контрольный журнал
Статический анализ Linux Нет Apple SDK и локальных Xcode-инструментов Команда, версия анализатора
Генерация кода Linux Все генераторы объявлены в графе Inputs и outputs
Swift-компиляция iOS-цели macOS Используется Apple SDK и rules_apple Toolchain и SDK
Simulator-тест macOS Требуется runtime Simulator Device, runtime, тестовый отчёт
Архивирование macOS Создаётся Apple archive Путь архива и checksum
Подпись и экспорт macOS Нужны identity и profile Identity, profile, export log

Вторая таблица показывает, какие показатели нужно собирать неделю перед расширением. Фиксированные числовые пороги здесь намеренно не задаются: их следует вывести из собственного SLA и размера очереди, а не выдавать за универсальные значения.

Показатель Что записывать Как трактовать
Cache hit По каждому типу action Низкое значение указывает на нестабильные inputs или новый узел
Ожидание Mac Время от постановки до старта Рост означает дефицит исполнителей либо неверный приоритет
Длительность стадий Компиляция, тесты, архив, экспорт Показывает настоящую, а не суммарную задержку
Retry rate Причина каждого повторного запуска Разделяет ошибки среды и ошибки кода
Восстановление Время и ручные действия после сбоя Указывает, можно ли считать узел серверным

Третья таблица связывает результат с архитектурным решением:

Наблюдение Рекомендуемый следующий шаг
Один проект, полный цикл проходит на одном Mac Оставить один удалённый Mac и документировать резервное восстановление
Linux выполняет независимые этапы, но Apple-очередь растёт Ввести гибридную маршрутизацию и измерить дополнительный Mac
Чистая сборка отличается на новом узле Не расширять кластер, пока не устранены скрытые зависимости
Подпись требует ручного GUI-входа Остановить production-внедрение и переделать secret flow
Кэш даёт результаты только на конкретном хосте Разделить ключи среды и описать все inputs
Сбой после перезапуска не восстанавливается Добавить автоматический retry либо заменить узел
11

FAQ для проектной команды

Полный iOS-граф должен иметь Xcode?

Да, если результатом является поставляемое приложение. Bazel может управлять графом, но Xcode предоставляет SDK и инструменты Apple. Без установленного и выбранного Xcode можно оставить только те этапы, которые не обращаются к Apple toolchain.

Может ли CI на Bazel 9 полностью работать в Linux?

Полностью — только если под «работать» понимать подготовительные действия. Для iOS-доставки Linux не заменяет macOS: компиляция Apple-целей, Simulator, архив, подпись и экспорт требуют отдельной проверки на Mac. Поэтому Linux остаётся полезной частью, но не единственным узлом полного контура.

Как доказать, что action действительно выполняется на macOS?

Нужно включить подробный вывод Bazel, сохранить action mnemonic, выбранную платформу, toolchain и сведения об исполнителе. Название job или shell-скрипта ничего не доказывает. Дополнительным подтверждением служат путь к SDK, версия Xcode и запись фактического executor в журнале CI.

Как подключить удалённый Mac к смешанному кластеру?

Сначала описывается платформа macOS с нужными ограничениями, затем исполнитель регистрируется в системе CI с установленными Bazel, rules и Xcode. После этого минимальный проект запускается с очищенным кэшем, а отдельно проверяются очередь, удалённое выполнение, кэш и восстановление. Доступ по SSH сам по себе кластером не является.

Что означает успешная приёмка Bazel iOS-узла?

Узел принят только после повторяемой чистой сборки, Simulator-тестов, архива, подписи, экспорта и восстановления после перезапуска. Если прошла лишь компиляция без подписи, это подготовительный исполнитель, а не production-узел. Все версии и секретные операции должны быть зафиксированы в протоколе без публикации самих ключей.

12

Практический вывод для выбора Mac-архитектуры

Linux остаётся выгодным местом для платформенно-независимых задач, но попытка держать там весь Bazel 9 iOS-процесс создаёт три системных недостатка: Apple SDK и Xcode оказываются вне естественной среды, подпись превращается в отдельный ручной обход, а успешная промежуточная сборка создаёт ложное ощущение готовности релиза. Виртуализация или случайно настроенный удалённый исполнитель добавляют риск рассинхронизации toolchain и скрытых зависимостей.

Реальный удалённый Mac закрывает именно этот пробел: он даёт постоянную macOS-среду для Apple action, но не отменяет необходимость описать платформы, секреты, кэш и тесты восстановления. Поэтому разумный путь — сначала прогнать на одной изолированной машине настоящий проект Bazel 9, зафиксировать результаты при чистой сборке, подписи, Simulator и перезапуске, а затем по фактической очереди решить, нужен ли постоянный арендованный узел или смешанный кластер Linux плюс macOS.

Если требуется временная среда для такой проверки, NodeMini можно рассматривать как способ получить отдельный Mac без немедленной покупки физического оборудования. После протокола приёмки команда сможет обоснованно выбрать срок аренды, количество узлов и границы кэша, а не масштабировать CI по предположениям.