Не переводите численность команды напрямую в число Mac-узлов: сначала соберите реальные данные очереди и выполнения, разделите нагрузку по сценариям и рассчитайте базовую ёмкость. На этой неделе выгрузите историю CI и проверьте расчёт на пилоте; дополнительные узлы арендуйте только тогда, когда измеренные ожидание, пики или ограничения изоляции это оправдывают.

Кому пригодится: IT-руководителю, который планирует ресурсы iOS CI и готовит заявку на закупку или аренду.
Платформенному инженеру, который настраивает маршрутизацию GitHub Actions Self-hosted Mac Runner и управляет очередями.
FinOps-руководителю, которому нужна проверяемая модель ёмкости и бюджета.

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

Оценка ёмкости узлов Mac для корпоративного iOS CI начинается не с количества разработчиков, а с заданий, которые действительно требуют macOS и Xcode. Сотрудники могут запускать PR-проверки с разной частотой; часть задач выполняется на обычных Runner, а часть вообще не создаёт отдельную сборку. Поэтому список сотрудников — слабая замена журналу workflow.

Для расчёта нужны как минимум объём запусков по типам, время ожидания, длительность выполнения, пиковое совпадение задач и доля заданий, которые нельзя безопасно объединить в один пул. Эти сведения берите из истории CI и событий workflow_job, а не из предположений о «среднем разработчике». В payload события доступны отметки постановки задания в очередь, начала и завершения выполнения; по ним можно вычислить ожидание и длительность каждого задания. Описание полей события workflow_job.

Для одного задания определите:

  • ожидание = started_at − queued_at;
  • длительность выполнения = completed_at − started_at;
  • полный цикл до завершения = completed_at − queued_at.

Это три разных показателя. Длинный полный цикл не всегда означает, что нужен дополнительный Mac: задержка может возникнуть до запуска на Runner, в тестовой зависимости или на этапе публикации. Сопоставляйте показатели с метками задания и фактическим состоянием очереди.

Сценарий Что измерять Ограничение, меняющее расчёт Подходящее свидетельство
PR и обычные сборки Частоту запусков, длительность, совпадение заданий Часть этапов можно выполнять не на Mac; маршрутизировать нужно только macOS/Xcode работу Журналы workflow и метки заданий
Симуляторы и регрессия Длительность тестов, число одновременных матричных заданий, ожидание Версии окружения, доступность симуляторов и нагрузка на один хост могут ограничить параллельность История тестов, конфигурация matrix, результаты пилота
Архивация, подпись и публикация Время выполнения и окна выпуска Права на сертификаты, защищённая среда и политика доступа могут запрещать общий пул Журналы релиза, настройки окружения и правила доступа
Пики и специализированные toolchain Очередь в периоды слияния и выпуска, долю несовместимых заданий Требования к версии macOS, Xcode или архитектуре ограничивают выбор Runner Метки, маршруты заданий и история очередей

PR и обычные сборки: Mac нужен не каждому этапу

Начните с декомпозиции workflow. Отдельно отметьте компиляцию, проверку проекта, подготовку зависимостей, линтеры, тесты и публикацию. Затем установите, какие шаги реально требуют macOS или Xcode. Если часть проверки может выполняться в другом окружении, не включайте её часы в расчёт ёмкости Mac.

В GitHub Actions задание направляется на Runner, который соответствует указанным требованиям; для Self-hosted Runner учитываются метки и группа. Если подходящего онлайн-Runner нет, задание ждёт в очереди. Это правило описывает маршрутизацию платформы, но само по себе не говорит, сколько узлов должна иметь ваша организация. Правила сопоставления Self-hosted Runner и очередь и описание меток для самоуправляемых Runner.

Как очередь GitHub Actions помогает оценить число Mac Runner? Сначала отделите очередь заданий, которым подходит конкретная группа и набор меток, от общего времени workflow. Затем сопоставьте время ожидания и длительность выполнения с тем, сколько подходящих Runner было доступно в соответствующий момент. Если задачи стоят, потому что метки слишком узкие или группа недоступна, добавление узлов в другой пул проблему не решит. Выбор Runner в workflow задаётся через группу и метки, поэтому проверьте фактическую конфигурацию маршрута. Документация о выборе Runner для задания.

Не смешивайте ограничения параллельности GitHub Actions с ёмкостью ваших Mac. Ограничения платформы для параллельных заданий и количество подходящих Self-hosted Runner — разные уровни планирования. Прежде чем арендовать узел, убедитесь, что требуемое задание вообще может стартовать по правилам платформы и что его маршрут ведёт в нужный пул. Официальные сведения об ограничениях GitHub Actions.

Симуляторы и регрессия: отдельная нагрузка на пул

Тестирование на симуляторах часто ведёт себя не так, как обычная сборка: задачи могут запускаться матрицей, повторяться после исправлений или объединяться в регрессионные пакеты. Считайте их отдельно, даже если они используют тот же репозиторий и ту же версию Xcode. Иначе средняя длительность сборки скроет длинные тестовые задания, которые занимают Runner во время пиков.

Для каждого класса тестов зафиксируйте:

  • количество запусков в обычный и интенсивный период;
  • длительность выполнения по фактическим журналам;
  • конфигурацию матрицы и число одновременно запланированных заданий;
  • требования к версиям macOS, Xcode, симуляторов и зависимостей;
  • ожидание в очереди до начала теста.

Не принимайте число элементов матрицы за гарантированное число параллельных процессов. Оно показывает потенциальный объём заданий, а не доступность свободных Runner и не безопасную производительность одного Mac. Параллельность подтвердите на пилотной конфигурации: если тесты мешают друг другу или нестабильны при совместном запуске, увеличивать общий пул без изменения маршрутизации бессмысленно.

Можно ли объединить PR, тесты на симуляторах и релизные задания? Можно, если все они совместимы по toolchain, доступу и требованиям изоляции, а измеренные очереди остаются приемлемыми. Разделяйте пулы, если тесты занимают узлы надолго, требуются отдельные версии окружения или релизные секреты нельзя предоставлять обычным заданиям. Для изоляции маршрутов проверьте, как Runner Group ограничивает доступ, и сопоставьте это с политикой репозитория и workflow. Назначение и контроль доступа Runner Group.

Подпись и публикация: безопасность задаёт доступность

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

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

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

Пики и специальные toolchain: резервируйте по доказанному сценарию

Краткий всплеск очереди и постоянная нехватка ёмкости требуют разных решений. Пики могут появляться во время массового слияния PR, подготовки релиза или запуска регрессии. Если ожидание быстро исчезает после короткого периода, постоянный дополнительный узел может простаивать. Если очередь повторяется и мешает целевому времени обратной связи, проверьте, какая именно категория заданий создаёт нагрузку.

Заранее определите допустимое ожидание для каждого приоритета. Это внутренний критерий команды, а не официальный показатель GitHub. Выберите его по рабочему процессу: PR-проверке может быть важна быстрая обратная связь, тогда как плановая регрессия может ждать свободное окно. После этого измеряйте долю заданий, выходящих за цель, и проверяйте предположение на пилоте.

Специализированные задачи выделяйте по свидетельствам, а не по названию проекта. Если workflow требует конкретную версию macOS, Xcode или архитектуру, используйте соответствующие метки и отдельные маршруты. Руководство GitHub по меткам Self-hosted Runner объясняет назначение меток, а описание Runner Scale Sets — подход к группам Runner, которые масштабируются под спрос.

Для изменяющейся нагрузки рассмотрите масштабирование как отдельный этап архитектуры, а не обещание автоматического устранения любой очереди. Официальная документация описывает настройку Runner Scale Sets и варианты расширения их ёмкости; применимость зависит от вашей инфраструктуры, маршрутов и эксплуатации. Инструкция по развёртыванию Runner Scale Sets. GitHub также описывает жизненный цикл и эксплуатационные особенности Self-hosted Runner — учитывайте их, если планируете временные экземпляры, а не постоянный пул. Справочник по Self-hosted Runner.

Модель, пилот и бюджет: от журналов к решению

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

Работа сценария за период = число заданий × типичная длительность выполнения.

Требуемая ёмкость = работа сценария с учётом её распределения во времени, допустимого ожидания и доступности совместимых Runner.

Первая формула даёт объём работы, но не готовое число узлов: одинаковое число минут может быть распределено равномерно или сосредоточено в окне выпуска. Вторая связывает объём с реальным расписанием и ограничениями. Для расчёта базовой ёмкости используйте типичную нагрузку, для пиковой — наблюдавшиеся интенсивные интервалы и отдельно обозначенное предположение о резерве. Не выдавайте ни одну оценку за показатель GitHub или VMSPIN.

Вариант планирования Что входит в оценку Когда он подходит Что проверить до решения
Базовая ёмкость Регулярные PR, обычные сборки и предсказуемые тесты Нагрузка распределена, а очередь укладывается во внутренние цели Маршруты, длительность, доступность подходящих Runner
Пиковая ёмкость Релизы, массовые слияния и регрессия Всплески повторяются и создают измеримое ожидание Длительность пика, приоритеты заданий и эффект дополнительного узла
Изолированная ёмкость Подпись, публикация или специальные toolchain Задания нельзя безопасно или технически объединить с общим пулом Группа доступа, секреты, метки, требования к окружению
Резерв или аренда по потребности Непостоянная нагрузка и пилотная проверка Покупка постоянной мощности не подтверждена журналами Доступность, сроки предоставления, условия и соответствие конфигурации

Проверка перед заявкой

  • [ ] Выгрузите историю заданий и отметьте queued_at, started_at и completed_at, чтобы отдельно видеть ожидание и выполнение.
  • [ ] Разделите workflow на шаги, требующие macOS/Xcode, и шаги, которые можно маршрутизировать иначе.
  • [ ] Сгруппируйте задания по PR, симуляторам, регрессии, подписи, публикации и специальным toolchain.
  • [ ] Сверьте метки и Runner Group с реальными workflow, включая задания с доступом к секретам.
  • [ ] Рассчитайте базовую нагрузку и пиковую отдельно; любое предположение о резерве явно пометьте как гипотезу.
  • [ ] Проведите пилот и сравните ожидание, длительность, повторные запуски и совместимость задач с исходной моделью.
  • [ ] Уточните, какая часть ёмкости должна быть постоянной, а какая нужна только в периоды пиков или для изоляции.

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

Решение о покупке, аренде или смешанной ёмкости

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

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

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