У вас уже есть GitLab (SaaS или self-managed), но сборки iOS/macOS застревают между очередями хостинговых macOS runner, ноутбуками «и так, и так» или развёртыванием Jenkins. Для платформенных инженеров с мышлением эксплуатации VPS этот гид открывает путь «арендовать Mac как узел»: семь чек-листов, чтобы вынести на поверхность реальное трение с GitLab Runner на выделенном удалённом Mac, сравнительная таблица с Jenkins SSH-агентами и self-hosted раннерами GitHub Actions, затем шестишаговый runbook передачи (регистрация, теги, каталоги кэша, concurrency и эскиз .gitlab-ci.yml) и перекрёстные ссылки на статьи о runner, Jenkins и управлении диском SwiftPM/Pods.
В документации GitLab gitlab-runner register выглядит гладко, но в продакшене время чаще съедает конечный автомат тулчейна Apple и параллельное топтание диска. Используйте семь пунктов ниже, чтобы превратить «давайте добавим runner» в таблицу рисков, которую можно подписать.
Считать удалённый Mac Linux-runner: игнор TCC, связки ключей и редких GUI-потребностей взрывает первую подпись — смотрите вместе с чек-листом SSH против VNC.
Регистрация под личной учётной записью macOS: сон, запросы обновлений и десктопные сессии ломают истинно безлюдные сценарии — нужен выделенный CI-пользователь по линии воспроизводимых сборок.
Планировать concurrency только по ядрам CPU: пики RAM Xcode и усиление записи NVMe кусаются раньше; без сегментированного DerivedData два задания могут взаимно заблокироваться — тот же контракт, что в управлении диском SwiftPM/Pods.
Игнорировать токены runner и гигиену регистрации: разбросанные бэкапы config.toml как открытый текст дают ложную уверенность, когда день ротации красит очереди.
Копировать политики кэша: плохие ключи cache: кросс-контаминируют ветки или вечно промахиваются — проектируйте ключи с измерениями ветки и lockfile.
Оставлять артефакты только на диске runner: без артефактов GitLab или объектного хранилища страдают диск и комплаенс — увяжите удержание с security review.
Нет «первого человеческого окна»: начальные профили подписи могут потребовать разового VNC или подтверждения на десктопе перед возвратом в headless — см. Fastlane + CI.
Общая причина — воспринимать «удалённый Mac» как сырую вычислительную мощность, а не хост с отпечатками Xcode и границами связки ключей. Ведите отпечатки образов, версии тулчейна, пороги очистки и контракты тегов runner так же, как реплики БД. Сочетайте с корпоративными пулами сборки: при совместном хосте нескольких проектов теги GitLab tags должны быть тоньше, чем «любой Mac», иначе resource_group не выразит реальную изоляцию.
Против GitHub Actions разница не в том, «соберётся ли», а в определении pipeline и источниках событий: .gitlab-ci.yml нативно привязан к жизненному циклу MR; Actions привязан к PR, но дорого мигрировать с GitHub. Если вы целиком на GitLab, macOS как shell runner обычно согласованнее, чем второй диалект Jenkins для iOS — тем не менее Jenkins иногда выигрывает корпоративные ревью оркестрации on-prem. Следующая таблица фиксирует компромиссы.
Перед регистрацией прочитайте разделы кэша и меток в нашем гайде по runner: большинство договорённостей по каталогам напрямую переносятся в cache GitLab и CI_PROJECT_DIR; меняется только триггер — с workflow на pipeline.
Серебряной пули нет — вы выбираете ментальную модель оркестрации и границу секретов. Зафиксируйте в ревью три SLA: задержка очереди, объяснимые сбои, стоимость ротации ключей.
| Измерение | GitLab Runner (macOS shell) | GitHub Actions self-hosted | Jenkins SSH-агент |
|---|---|---|---|
| Определение pipeline | .gitlab-ci.yml нативен для проектов/MR; шаблоны и includes зрелые | YAML в репозитории плотно связан с событиями PR/Issue | Job DSL / Pipeline Groovy — гибкая кросс-репозиторная оркестрация, но выше дрейф стиля |
| Модель регистрации | Токены проекта/группы; config.toml централизует executor и теги | Токены runner уровня org/repo со сравнительно стандартной настройкой | Контроллер держит SSH-учётные данные — укрепляйте control plane |
| Concurrency и throttling | resource_group, parallel, лимиты concurrency runner | Матрицы и concurrency в YAML | Метки + плагины throttling — гибко, но тяжело в конфигурации |
| Кэш и артефакты | Нативные cache/artifacts; плохие ключи отравляют кэши | Богатая экосистема actions/cache и артефактов | Часто самодельная склейка к объектным хранилищам |
| Лучше всего подходит | Организации вокруг GitLab, нужны MR pipeline и единые пулы runner | Ориентация на GitHub, доставка на событиях PR | Несколько продуктовых линий, on-prem артефакт-хранилища, согласования, смешанные Git-хосты |
Арендовать Mac «как VPS» в терминах GitLab значит купить профиль регистрируемого runner: фиксированный SSH, предсказуемые уровни диска и возможность вшивать отпечатки Xcode в теги.
Если побеждает GitLab Runner, относитесь к tags как к первоклассным сущностям: минор Xcode, разрешён ли тяжёлый pod install, идут ли UI-тесты — всё должно быть явным. Сочетайте с снимками против долгоживущих узлов: долгоживущие runner опираются на инкрементальную очистку; золотые образы — на прогретые образы и дымовые тесты отката.
При нескольких CI унифицируйте сегментацию DerivedData, чтобы задания GitLab не топтали задания Jenkins или Actions на том же удалённом Mac — разные Unix-пользователи или корни, а не «надежда на сдвиг расписаний».
Порядок важен: сначала идентичность и каталоги, затем регистрация и теги, последним — concurrency — синхронизируйте скрипты отпечатков с воспроизводимыми сборками, чтобы GitLab валидировал стабильную подпись, а не только «git clone работает».
Создать выделенного пользователя и корень работы: например /Users/ci/gitlab-runner, не смешивать с личным ~/Desktop; только SSH по ключу.
Установить gitlab-runner: официальный пакет macOS или Homebrew; бинарь в PATH и запускается под сервисной учётной записью (launchd).
Выполнить register: выбрать executor shell, указать URL GitLab и registration token; закрепить tag_list (напр. ios,shell,m4) интерактивно или флагами.
Первое задание health-check: вывести xcode-select -p, xcodebuild -version, swift --version и снимки диска; лог сохранить как доказательство приёмки runner.
Явно задать DerivedData в .gitlab-ci.yml: тот же контракт, что в управлении диском SwiftPM/Pods — сегмент на проект, избегать общих путей по умолчанию.
Задать таймауты, артефакты и очистку: timeout, удержание при сбое и останов линии при низком диске (мониторинг + API паузы runner).
stages: [build]
variables:
DERIVED_DATA: "$CI_PROJECT_DIR/.derivedData/$CI_PIPELINE_ID"
build_ios:
stage: build
tags: [ios, shell, m4]
timeout: 45m
script:
- xcode-select -p
- xcodebuild -version
- df -h
- xcodebuild -scheme "App" -configuration Release -destination "generic/platform=iOS" -derivedDataPath "$DERIVED_DATA" build
artifacts:
when: on_failure
paths:
- "**/*.xcresult"
expire_in: 3 days
Совет: если pipeline также выкладывает в сторы, прочитайте Fastlane + CI и согласуйте пользователей сборки, разделы связки ключей и ключи App Store Connect API с переменными GitLab CI/CD (mask + protect секретов).
При обновлениях GitLab или runner прогоните канареечное iOS-задание на том же коммите до/после и сравните вывод отпечатков и распределение времени сборки. Напротив кэширования runner: слишком свободные ключи кэша GitLab позволяют ветке A отравить кэш Pods ветки B; слишком жёсткие означают бесконечные холодные старты — платформа и продукт должны согласовать уровни удержания.
Если провайдер задаёт фиксированные SSH-порты и non-root пользователей, централизуйте параметры подключения во внутреннем runbook, а не в разрозненных описаниях переменных — ротируйте в одном месте. Вместе с Jenkins + удалённый Mac: базовые линии SSH (ключи, firewall, аудит) должны быть единым источником на всех CI-стеках, а не тремя диалектами.
resource_group и throttling тяжёлых установок зависимостейТипичная ошибка — мерить concurrency по тому, «сколько процессов xcodebuild помещается». pod install / разрешение SPM и пики компиляции часто в разных фазах — выражайте mutex-ресурсы в .gitlab-ci.yml через resource_group или разделяйте задания. С управлением SwiftPM/Pods: отдельно ограничивайте тяжёлые resolve-задания, чтобы они не отнимали слоты у частых зелёных сборок.
Тесты — ещё одно скрытое измерение: UI-тесты Simulator требуют иной модели concurrency, чем только компиляция — читайте шардирование XCTest и Simulator и изолируйте выделенными тегами или пулами runner в GitLab.
Предупреждение: не продолжайте забивать очередь, когда диск ниже безопасных порогов — сначала приостановите планирование и очистите, иначе рискуете наполовину записанным состоянием Xcode/git, дороже краткой очереди.
Если runner в нескольких регионах, кодируйте регион в именах и тегах и маркируйте пути артефактов, чтобы крупные межрегиональные передачи не читались как сбои сборки. С покупка против аренды TCO: задержка и исходящий трафик с самого начала входят в модель затрат.
Используйте пункты ниже для внутреннего выравнивания; подстройте пороги под размер репозитория и параллелизм.
gitlab-runner --version, xcodebuild -version, Ruby/Bundler при CocoaPods, модель диска; после изменений — канареечный pipeline.Офис-only Mac страдают от сна, джиттера сети и дрейфа тулчейна; Linux не может хостить официальный iOS-тулчейн Apple. Удерживая GitLab в привычном web/MR-потоке и перенося выполнение macOS на выделенные, постоянно включённые, доступные по SSH удалённые узлы, вы превращаете «единый источник истины pipeline» из лозунга в контракт. По сравнению с ад-хок своим железом или хрупкими виртуализированными стеками Xcode облачная аренда Mac Mini NodeMini часто сильнее как платформенный ход: конечные точки SSH, уровни диска и воспроизводимые профили runner яснее; сравните спецификации и цены в тарифах аренды, онбординг завершите в справочном центре.
Привяжите этот runbook к внутренним уровням изменений тулчейна: патч/минор/мажор Xcode соответствуют разным согласованиям, объёму канарейки и политикам инвалидации кэша.
Большинство нативных команд iOS/macOS начинают с shell executor ради минимального трения с Xcode, связкой ключей и Simulator. Docker подходит контейнеризованным стекам или более жёсткой изоляции, но на тулчейне Apple дороже. Сначала сравните уровни железа в тарифах аренды.
Не ориентируйтесь только на ядра: замерьте пик RAM и усиление записи NVMe для одного задания, затем смотрите P95 при росте concurrency; сегментируйте DerivedData и кэши зависимостей, тяжёлые pod install ограничивайте отдельно. Вопросы онбординга — справочный центр.
GitLab связывает токены runner проекта/группы с .gitlab-ci.yml; Jenkins опирается на корпоративную оркестрацию и плагины; Actions плотно привязан к событиям PR. Документируйте источники событий, границы секретов и SLA очередей — не логотипы. Продолжайте с Jenkins + удалённый Mac и раннерами GitHub Actions.