Как настроить GitLab Runner на Mac для сборок iOS
Чтобы запускать задачи GitLab CI на Mac, установите официальный бинарник gitlab-runner и зарегистрируйте его с shell executor. Сначала создайте раннер в настройках CI/CD проекта, и вы получите токен glrt-. Затем установите его как пользовательский LaunchAgent и включите автоматический вход, чтобы он возвращался после перезагрузки. Выполняйте установку из терминала на рабочем столе Mac, а не по SSH. Этого требует документация GitLab.
Что нужно заранее
- Mac с Apple silicon, права администратора и установленный Xcode.
- Выполненный первый запуск Xcode. Если не уверены, один раз выполните
sudo xcodebuild -runFirstLaunch. - Права на управление раннерами в вашем проекте или группе GitLab.
- Сессия рабочего стола на Mac, через демонстрацию экрана или монитор. Страница установки на macOS в документации GitLab велит использовать локальный графический терминал, а не сессию SSH.
- Учётная запись macOS, под которой будут идти задачи. Войдите на рабочий стол под этим пользователем.
1. Скачайте бинарник раннера
GitLab пишет, что не поддерживает формулу Homebrew, и советует официальный бинарник. На Apple silicon берите сборку arm64. На новом Mac папки /usr/local/bin может ещё не быть, поэтому сначала создайте её.
sudo mkdir -p /usr/local/bin sudo curl --output /usr/local/bin/gitlab-runner \ "https://s3.dualstack.us-east-1.amazonaws.com/gitlab-runner-downloads/latest/binaries/gitlab-runner-darwin-arm64" sudo chmod +x /usr/local/bin/gitlab-runner gitlab-runner --version
2. Создайте раннер в GitLab
Токены регистрации раннеров устарели. GitLab планирует убрать их в GitLab 20.0. Сейчас раннер сначала создают в интерфейсе, а потом получают токен аутентификации раннера. Этот токен начинается с glrt-.
- В проекте откройте Settings, затем CI/CD, затем раскройте Runners.
- Выберите Create project runner и укажите macOS.
- В поле Tags введите
macos, xcode. Оставьте Run untagged jobs выключенным, чтобы сюда попадали только задачи, которые просят Mac. - Нажмите Create runner и скопируйте токен. Он показывается совсем недолго.
Теги теперь хранятся у раннера в GitLab. Документация GitLab говорит, что такие настройки, как --tag-list и --run-untagged, задаются только при создании раннера, в интерфейсе или через API. Позже теги меняют на странице Edit раннера.
3. Зарегистрируйте с shell executor
Страница установки на macOS в документации GitLab рекомендует shell executor для сборок iOS и macOS. Задачи выполняются прямо на Mac, от вашего пользователя, с Xcode и симуляторами. Регистрация без вопросов выглядит так:
export RUNNER_TOKEN="glrt-paste-your-token-here" gitlab-runner register \ --non-interactive \ --url "https://gitlab.com/" \ --token "$RUNNER_TOKEN" \ --executor "shell" \ --description "mac-mini-m6"
Для self-managed GitLab укажите URL своего инстанса. Настройки попадают в ~/.gitlab-runner/config.toml. GitLab отмечает, что shell executor находится в режиме поддержки. Он по-прежнему получает исправления безопасности, и страница про macOS всё ещё рекомендует его для работы с Xcode.
4. Установите и запустите службу
cd ~ gitlab-runner install gitlab-runner start gitlab-runner status
Это создаёт ~/Library/LaunchAgents/gitlab-runner.plist. На macOS раннер это пользовательский LaunchAgent, и GitLab говорит, что другой режим не поддерживается. Он работает от вашего имени, а не от root. Ему доступны ваша связка ключей и сессия пользователя, а они нужны iOS Simulator и подписи кода. Логи пишутся в ~/Library/Logs/gitlab-runner.out.log и gitlab-runner.err.log.
5. Сделайте так, чтобы он переживал перезагрузку
LaunchAgent запускается, когда его пользователь входит в систему, и останавливается при выходе. Поэтому после перезагрузки раннер вернётся, только если этот пользователь войдёт сам. Именно поэтому документация GitLab советует включить автоматический вход. Сделайте это в System Settings, в разделе Users and Groups. Затем запретите Mac засыпать и проверьте настоящей перезагрузкой.
sudo pmset -a sleep 0 sudo shutdown -r now # after it comes back, over SSH: gitlab-runner status
У автовхода на headless Mac есть несколько тихих сбоев, в том числе один новый в macOS 27. Мы описали их в статье об автовходе на headless Mac.
6. .gitlab-ci.yml для iOS-приложения
Задача попадает на раннер, только если у раннера есть все теги, которые указаны в задаче. Эта задача просит macos, запускает тесты и сохраняет result bundle, даже когда тесты падают.
stages:
- test
ios_tests:
stage: test
tags:
- macos
script:
- xcodebuild -version
- rm -rf build/TestResults.xcresult
- xcodebuild test -project MyApp.xcodeproj -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.5' -resultBundlePath build/TestResults.xcresult
artifacts:
when: always
paths:
- build/TestResults.xcresult
expire_in: 1 weekСтрока rm -rf важна на машине, которая хранит рабочую копию. xcodebuild отказывается перезаписывать существующий result bundle. Мы проверили это на Xcode 26.6.
Частые ошибки и их решения
Они взяты из раздела про устранение неполадок на macOS в документации GitLab.
"launchctl" failed: Could not find domain for. Вы запустили install или start по SSH. Откройте Terminal на рабочем столе Mac и выполните их там.FATAL: Failed to start gitlab-runner: exit status 134. Служба установлена неправильно. Выполнитеgitlab-runner uninstall, затем install, затем start, с рабочего стола.killed: 9на Apple silicon. Папки для логов, указанные в plist, должны существовать и быть доступны вашему пользователю на запись.Failed to authorize rights (0x1) with status: -60007. ВыполнитеDevToolsSecurity -enableиsudo security authorizationdb remove system.privilege.taskport is-developer.- git fetch зависает. Git из Homebrew может добавить credential helper со связкой ключей. Выполните
git config --global --add credential.helper ''от пользователя раннера. - Задача висит и не стартует. Её теги не совпадают с тегами раннера. Или у задачи нет тегов, а раннер не берёт задачи без тегов.
Чем помогает выделенный Mac
Shell executor использует одну и ту же машину для каждой задачи. DerivedData от Xcode, загруженные Swift-пакеты и кэши CocoaPods остаются на диске между пайплайнами. Именно туда уходит время. В нашем тесте с iOS-приложением Wikipedia на Xcode 26.6 мы замерили типичную задачу после небольшого изменения. На прогретом M6 она заняла 27 секунд. Та же задача заняла 269 секунд на свежем hosted раннере macos-26 у GitHub. Чистая сборка заняла 86 секунд против 183.
Когда хватает hosted раннеров Mac от GitLab
У GitLab есть свои раннеры macOS. В документации, которую мы читали в октябре 2026 года, они указаны как бета. Они доступны клиентам Premium и Ultimate и программам для open source. Есть два размера: M1 с 4 vCPU и 8 GB и M2 Pro с 6 vCPU и 16 GB. Если вы на одном из этих планов и запускаете несколько пайплайнов в день, hosted раннеры избавят вас от всех шагов выше.
Не берите выделенный Mac с shell executor для публичного проекта, который запускает чужие merge request. GitLab предупреждает, что задачи shell могут читать код других проектов на той же машине. MacRun вам также не подойдёт, если нужен статический IP для белых списков, SLA или больше одного региона. Ничего из этого мы не предлагаем.
Готовы попробовать на нашем железе? Страница о других CI-системах описывает сторону MacRun, а на странице цен есть все конфигурации.
Частые вопросы
Устанавливать ли GitLab Runner на macOS через Homebrew?
+
GitLab советует официальный бинарник. В документации сказано, что GitLab не поддерживает формулу Homebrew.
Почему gitlab-runner install не работает по SSH?
+
Раннер это пользовательский LaunchAgent, и ему нужна графическая сессия пользователя. Выполняйте install и start из терминала на рабочем столе Mac.
Может ли GitLab Runner работать на macOS как LaunchDaemon?
+
Нет. GitLab говорит, что поддерживается только пользовательский LaunchAgent. Задачам нужны связка ключей и сессия пользователя для подписи и Simulator.
Где задавать теги раннера при новой схеме с токеном?
+
В GitLab, на странице создания или редактирования раннера. Документация GitLab говорит, что теги задаются только при создании раннера в интерфейсе или через API, а не командой register.