Как запустить self-hosted раннер CircleCI на Mac
CircleCI machine runner 3 ставится на macOS из Homebrew tap от CircleCI и работает как LaunchAgent. Создайте namespace и resource class, скопируйте токен, впишите его в config.yaml раннера и запустите службу через bootstrap. Задачи попадают на него через machine: true и resource_class: namespace/name.
Что нужно заранее
- Права администратора организации в CircleCI. Администратор должен принять условия для раннеров в разделе Org, затем Runners. Только после этого появится меню.
- Хотя бы один кредит на счёте. CircleCI пишет, что задачи на раннерах не расходуют кредиты, но хранилище и сетевой трафик могут.
- Mac с Apple silicon, права администратора, Homebrew и Xcode.
sha256sum, который CircleCI указывает в требованиях. Установите его черезbrew install coreutils.
1. Создайте namespace и resource class
В веб-интерфейсе откройте Runners и выберите Create Resource Class. У каждой организации один namespace. Если вы публикуете orbs, он у вас уже есть. Назовите resource class, например, mac-mini-m6. Сохраните и скопируйте токен. CircleCI показывает его только один раз.
То же самое делает CLI:
circleci namespace create <name> --org-id <your-organization-id> circleci runner resource-class create <namespace>/<resource-class> <description> --generate-token
2. Установите раннер через Homebrew
brew tap circleci-public/circleci brew trust circleci-public/circleci brew install circleci-runner
Средняя строка новая. Homebrew 7.0.7, версия на нашем Mac в октябре 2026 года, отказывается загружать пакеты из стороннего tap, пока вы ему не доверитесь. На странице CircleCI этого шага пока нет. Раннер ставится как Homebrew cask.
macOS может показать уведомление, что добавлен фоновый объект от Circle Internet Services. Так и должно быть. Homebrew также записывает plist для LaunchAgent в ~/Library/LaunchAgents/com.circleci.runner.plist.
3. Добавьте токен в config.yaml
nano $HOME/Library/Preferences/com.circleci.runner/config.yaml
runner: name: "mac-mini-m6" working_directory: "/Users/$USER/Library/com.circleci.runner/workdir" cleanup_working_directory: true api: auth_token: "your-resource-class-token"
Когда cleanup_working_directory включён, каждая задача начинается с чистого checkout. DerivedData от Xcode по умолчанию лежит в ~/Library/Developer/Xcode/DerivedData, поэтому кэши сборки всё равно сохраняются. Если вы передаёте -derivedDataPath внутри рабочей папки, очистка удаляет её после каждой задачи.
Защитите токен
Токен resource class позволяет машине забирать задачи этого класса. Любой, кто его прочитает, может подключить свою машину и получать ваши задачи вместе с вашими секретами. Закройте доступ к файлу конфигурации для всех, кроме своего пользователя. Если токен утёк, смените его.
chmod 600 $HOME/Library/Preferences/com.circleci.runner/config.yaml ls -l $HOME/Library/Preferences/com.circleci.runner/config.yaml
Та же логика касается задач. Они выполняются от пользователя macOS, который запустил раннер, на том же диске, что и всё остальное. Направляйте на этот resource class только проекты, которым вы доверяете.
4. Подтвердите нотаризацию
Бинарник скачан из интернета, поэтому macOS должна его одобрить. CircleCI описывает, как сначала проверить подпись, а потом снять флаг карантина.
spctl -a -vvv -t install "$(brew --prefix)/bin/circleci-runner" sudo xattr -r -d com.apple.quarantine "$(brew --prefix)/bin/circleci-runner"
Первая команда должна ответить accepted, с источником Notarized Developer ID.
5. Запустите раннер в GUI-домене
Выполните эти команды из Terminal на рабочем столе Mac. GUI-домен это сессия рабочего стола пользователя, который вошёл в систему. Именно там живут Simulator и связка ключей входа.
launchctl bootstrap gui/$(id -u) $HOME/Library/LaunchAgents/com.circleci.runner.plist launchctl enable gui/$(id -u)/com.circleci.runner launchctl kickstart -k gui/$(id -u)/com.circleci.runner launchctl print gui/$(id -u)/com.circleci.runner
CircleCI описывает ещё вариант с user-доменом для headless сессий. Он переносит plist в /Library/LaunchAgents. На macOS 27 мы видели, как plist в этой папке ломает автовход при каждой загрузке. Подробнее в статье об автовходе на headless Mac. Для работы с iOS мы советуем GUI-домен с автоматическим входом.
6. Сделайте так, чтобы он переживал перезагрузку
Plist в ~/Library/LaunchAgents загружается, когда его пользователь входит в систему. Включите автоматический вход для этой учётной записи в System Settings, в разделе Users and Groups. Отключите сон командой sudo pmset -a sleep 0. Перезагрузите один раз и снова проверьте launchctl print. Логи лежат в ~/Library/Logs/com.circleci.runner/runner.log.
7. Направьте задачу на Mac
version: 2.1
jobs:
ios-tests:
machine: true
resource_class: your-namespace/mac-mini-m6
steps:
- checkout
- run:
name: Run tests
command: |
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
- run:
name: Zip result bundle
when: always
command: ditto -c -k --keepParent build/TestResults.xcresult TestResults.xcresult.zip
- store_artifacts:
path: TestResults.xcresult.zip
workflows:
ios:
jobs:
- ios-testsДокументация CircleCI называет два обязательных поля для задачи на раннере: machine: true и resource_class. Ключа macos: xcode: здесь нет, потому что образ вы не выбираете. Задача использует тот Xcode, который выбран на Mac. На Mac от MacRun это Xcode 26.6 со средой выполнения симулятора iOS 26.5.
Частые ошибки и их решения
Refusing to load cask ... from untrusted tap. Выполнитеbrew trust circleci-public/circleci, затем установите снова.- macOS блокирует бинарник. Вы пропустили шаг с нотаризацией. Выполните команду
xattrвыше. - Задачи стоят в очереди и не стартуют. Проверьте, что resource class в config.yml совпадает с созданным, затем прочитайте
runner.log. - Кэширование слоёв Docker не работает. CircleCI указывает, что на self-hosted раннерах оно не поддерживается.
xcodebuild: error: Existing file at -resultBundlePath. Удалите старый bundle перед шагом с тестами. Мы столкнулись с этим на Xcode 26.6.
Чтобы остановить раннер, выполните launchctl bootout gui/$(id -u)/com.circleci.runner. Чтобы удалить его, выполните brew uninstall --cask circleci-public/homebrew-circleci/circleci-runner.
Чем помогает выделенный Mac
Главный выигрыш дают прогретые кэши. В нашем тесте мы собирали iOS-приложение Wikipedia на Xcode 26.6. Типичная задача после небольшого изменения заняла 27 секунд на прогретом M6. На свежем hosted раннере macos-26 у GitHub она заняла 269 секунд. Чистая сборка заняла 86 секунд против 183.
Когда хватает hosted macOS от CircleCI
У CircleCI есть свои executor на Mac. В документации, которую мы читали в октябре 2026 года, указаны m4pro.medium с 6 vCPU и 28 GB и m4pro.large с 12 vCPU и 56 GB. У обоих больше памяти, чем у нашего M6 с 16 GB. Если вашим тестам нужно столько памяти или вы собираете несколько раз в неделю, оставайтесь на hosted. MacRun вам также не подойдёт, если нужны SLA, статический IP или несколько регионов.
Сторона настройки MacRun описана на странице о других CI-системах. Или сравните стоимость на своих минутах.
Частые вопросы
Self-hosted раннер CircleCI бесплатный?
+
CircleCI пишет, что выполнение на раннерах не расходует кредиты. На счёте нужен хотя бы один кредит, потому что хранилище и сетевой трафик всё равно могут оплачиваться.
Где лежит конфигурация раннера CircleCI на macOS?
+
В $HOME/Library/Preferences/com.circleci.runner/config.yaml. Логи пишутся в $HOME/Library/Logs/com.circleci.runner/runner.log.
Что выбрать: GUI-домен или user-домен?
+
Для сборок iOS GUI-домен с автоматическим входом. Он работает внутри сессии рабочего стола, которая нужна Simulator и связке ключей входа.
Работает ли кэширование слоёв Docker на self-hosted раннере CircleCI?
+
Нет. CircleCI указывает, что на self-hosted раннерах кэширование слоёв Docker не поддерживается.