DevOps & Audit 26 марта 2026 г.

Гайд 2026: шардирование iOS UI-тестов по облачным узлам Mac mini M4

NodeMac Team

Специалисты по мобильному CI

Мобильные релизы тормозят, если один Mac гоняет все UI-тесты последовательно. В этом гайде — когда окупается шардирование, сравнение одного узла и распределённого парка в одной матрице, контракт меток runner и бюджетов времени, а также восемь шагов, как разнести XCTest UI по выделенным облачным Mac mini M4 с предсказуемой математикой очередей.

Если вы стандартизируетесь на самохостных runner’ах GitHub Actions, шардирование превращает «один быстрый Mac» в парк, который успевает проверить pull request до того, как ревьюеры переключат контекст. Для более широкого параллелизма сборки см. параллельные Mac-узлы для CI/CD.

Почему даже мощный Mac не попадает в SLA по UI-тестам

Xcode агрессивно параллелит unit-тесты, но UI-тесты тратят время на запуск симуляторов, анимации и ожидание SpringBoard — нагрузка нелинейно растёт с числом ядер на одном хосте.

  • Конкуренция за GPU симулятора: три UI-сьюта одновременно на M4 часто выводят кадры за порог 33 мс, из-за чего тапы становятся нестабильными и падают ложные тесты.
  • Раздувание диска: каждый шард дублирует запись DerivedData; без 500 ГБ+ запаса на SSD параллельные джобы рушатся, когда свободно меньше ~15 %.
  • Непрозрачная очередь: без меток на шард непонятно, медленный PR из-за UI-инфраструктуры или сборки — перепроцаривают compile-runner’ы и всё равно не укладываются в UI.

Матрица решений: один Mac против шардированного парка

Критерий Один M4 «всё в одном» Выделенные Mac под UI-шарды
Wall-clock для UI-сьюта 90 мин Серия ≈ 90 мин 3 шарда ≈ 35–40 мин при балансе
Чувствительность к флакам Высокая под нагрузкой Ниже при одном сьюте на машину
Сложность эксплуатации Низкая Средняя; нужны метки и дашборды
Лучшая география Любая Шарды в HK / JP / KR / SG / US рядом с разработчиками

Разбейте тесты на корзины до закупки железа

Шардирование — это планирование, замаскированное под инфраструктуру. Делите сьюты на корзины со сопоставимой дисперсией длительности — цель ±20 % от медианы, чтобы один шард не был вечным аутсайдером.

  1. Экспортируйте историю длительностей из Xcode Cloud, логов XCTest или БД CI; сортируйте по p95.
  2. Выделите тяжёлые login-сценарии в отдельную корзину, чтобы не блокировать checkout и настройки, которые можно гонять параллельно.
  3. Помечайте тесты с физическими лабораториями отдельно — облачные Mac mini сильны в симуляторах, не в USB-фермах.
  4. Ограничивайте размер корзины бюджетом PR; если корзина всё ещё дольше 25 минут, делите по фиче-модулю.
  5. Версионируйте карту корзин в Git (ui-shards.json) для воспроизводимых перезапусков.

Совет: Держите compile- и UI-шарды на разных метках. Смешивание даёт сюрпризы в очередях, когда тяжёлый xcodebuild test забирает машину с таймаутами под симулятор.

Контракт меток runner для UI-шардов

Набор меток Назначение Пример runs-on
self-hosted, macOS, m4, ios-compile Только сборка + unit-тесты [self-hosted, macOS, m4, ios-compile]
self-hosted, macOS, m4, ios-ui, shard-1 UI-корзина A [self-hosted, macOS, m4, ios-ui, shard-1]
self-hosted, macOS, m4, ios-ui, shard-2 UI-корзина B Тот же шаблон для B/C/D …

Матрица GitHub Actions без случайного двойного планирования

Часто шарды задают измерением matrix. Типичный провал: и shard: [1,2,3], и широкий runs-on, попадающий на все Mac — GitHub может посадить несколько шардов на один хост и свести на нет бюджет на железо. Привяжите каждую ветку матрицы к уникальной метке или переменным репозитория 1:1 к hostname.

strategy:
  matrix:
    shard: [1, 2, 3]
    include:
      - shard: 1
        runner_labels: [self-hosted, macOS, m4, ios-ui, shard-1]
      - shard: 2
        runner_labels: [self-hosted, macOS, m4, ios-ui, shard-2]
      - shard: 3
        runner_labels: [self-hosted, macOS, m4, ios-ui, shard-3]
jobs:
  ui-tests:
    runs-on: ${{ matrix.runner_labels }}
    timeout-minutes: 40

Добавьте правило репозитория, отклоняющее workflow без метки shard-* на UI-джобах — одна политика спасает от добровольного схлопывания параллелизма. Арендуя Mac mini во втором регионе (например Сингапур при ревьюерах в Токио), дублируйте схему меток по региону (shard-1-sg), чтобы близость сети была явной в YAML.

Восемь шагов: UI-шарды на облачном Mac mini M4

Предполагается SSH к хостам Mac mini M4 NodeMac. Паттерны подключения — в справочном центре.

  1. Выделите N машин: целевое число шардов плюс один горячий резерв под flaky-перезапуски.
  2. Одинаковые сборки Xcode и runtime симуляторов заранее; дрейф между шардами даёт ложные «у меня на runner прошло».
  3. Регистрируйте GitHub runner’ы с уникальными именами и только нужной меткой шарда.
  4. timeout-minutes в workflow — стартуйте с 40 для UI и ужимайте по p95.
  5. Передавайте id шарда в xcodebuild через схемы или тест-планы (списки -only-testing на корзину).
  6. Отключите сон экрана и обеспечьте GUI-сессии для CI-пользователя, если это требует harness; зафиксируйте в security review.
  7. Складывайте артефакты централизованно (JUnit, скриншоты) с именем шарда в файле для триажа.
  8. Алерт на перекос: если один шард на 1,5× дольше остальных три прогона подряд — перебалансируйте корзины.

KPI и SLO для шардированного парка

Без метрик шардирование превращается в слепую закупку железа. Задайте SLO на «PR с зелёным UI» (например p95 меньше 45 минут) и измеряйте отдельно ожидание в очереди runner, чистое время тестов и загрузку артефактов. Дашборды по метке ios-ui покажут, не хватает ли шардов или корзины перегружены.

Еженедельный разбор десяти самых медленных тестов часто выгоднее нового Mac. Узлы NodeMac в Гонконге, Японии, Корее, Сингапуре и США снижают сетевую задержку; сочетайте региональные runner’ы с расчётом очереди выше вместо складывания всего в один часовой пояс.

Складывайте JUnit и сводки по шардам в тот же бэкенд артефактов, что и unit-тесты, чтобы видеть тренды за недели. Если p95 резко подскочил, сопоставьте с обновлениями Xcode или macOS на хостах шардов — это чаще даёт скрытые регрессии, чем свежие коммиты в приложении.

FAQ

Сколько шардов UI-тестов помещается на один Mac mini M4?

Считайте каждый тяжёлый по симулятору UI-шард основным заданием на машину, если нет замеров запаса; два шарда возможны для лёгких наборов, но конкуренция за GPU и диск часто съедает выигрыш по wall-clock.

Нужно ли шардам те же метки runner, что и чисто сборочным джобам?

Нет—используйте отдельные метки вроде ios-ui-shard, чтобы сборочные джобы не забирали машины с дополнительными симуляторами и предположениями о GUI-сессии.

Нужны машины в нескольких минутах от команд в Гонконге, Токио, Сеуле, Сингапуре или США? Сравните тарифы NodeMac, чтобы согласовать число шардов с логикой очереди, а не гадать.

Mac mini M4 — практичная единица шардирования для iOS UI: Apple Silicon даёт сильный single-thread для XCTest, unified memory под несколько сервисов симулятора и эффективный простой между всплесками PR. NodeMac сдаёт в аренду выделенные физические Mac mini с SSH и VNC в HK, JP, KR, SG и US — каждый шард это реальное железо для удалённой отладки. Аренда по требованию снижает CapEx, пока вы проверяете карту шардов и балансируете корзины по телеметрии.

Добавьте выделенные UI-шарды

Арендуйте Mac mini M4 в HK·JP·KR·SG·US, разметьте runner’ы по шардам и сократите wall-clock XCTest UI с предсказуемыми очередями.

NM
NodeMac Cloud Mac
Развёртывание за 5 мин

Аренда выделенного Mac на Apple Silicon в облаке. SSH/VNC, узлы HK·JP·KR·SG·US.

Начать