Если коротко: iOS CI в GitHub Actions тормозит не потому, что ваш проект «слишком тяжелый», а потому что сборочная цепочка iOS плохо живет в эфемерной среде. Pods, Xcode, подписи, экспорт IPA, загрузка в TestFlight — все это любит постоянный Mac с прогретым кэшем. Поэтому self-hosted runner на Mac — это не «опция для энтузиастов», а реальный способ ускорить и стабилизировать pipeline. По теме также полезно: TCO self-hosted runner, Flutter iOS CI, медленная сборка Xcode и инфраструктурный контекст в войне ИИ-инфраструктуры.
1) Почему iOS CI на GitHub Actions часто медленный
Главная проблема — отсутствие постоянства. Hosted runner поднимается «с нуля», кэши попадают нестабильно, а iOS-цепочка чувствительна к любому промаху кэша. В итоге один и тот же workflow может занимать 14 минут сегодня и 26 завтра.
2) На каких шагах теряется время
| Этап | Типичное время | Почему на hosted дольше |
|---|---|---|
pod install | 4–12 мин | Часто заново тянутся зависимости и Specs |
xcodebuild archive | 8–20 мин | DerivedData не успевает «разогреться» |
| Signing / Export | 2–8 мин | Повторная инициализация keychain и профилей |
| Upload TestFlight | 2–10 мин | Плавающая сеть и очередь загрузки |
3) Рабочая архитектура: Linux для тестов, Mac для iOS-релиза
Рекомендуемая архитектура GitHub Actions для iOS CI
lint · tests · Android
Какие кэши держать на runner
- CocoaPods cache +
Pods DerivedData- Ruby/Bundler и build-инструменты
4) Как настроить self-hosted runner, чтобы реально ускориться
- Фиксированная машина и пути: иначе кэш не будет стабильно попадать.
- Зафиксированные версии: Xcode, CocoaPods, Ruby без «дрейфа».
- Ограниченная параллельность: обычно 1–2 iOS job на один Mac.
- Тяжелые обновления отдельно:
pod repo updateв плановом job. - Контроль диска: чистка архивов и DerivedData по расписанию.
Из официальных источников: GitHub про self-hosted runners и Apple Xcode Release Notes.
5) До / после: hosted против self-hosted
| Среда | Первый билд (cold) | Второй билд (warm cache) | Стабильность |
|---|---|---|---|
| GitHub hosted macOS | 16–24 мин | 14–20 мин | Средняя |
| Mac mini M4 self-hosted | 14–22 мин | 5–9 мин | Высокая |
6) Пример workflow для iOS релиза
name: release-ios
on:
push:
branches: [main]
tags: ['v*']
jobs:
ios:
runs-on: [self-hosted, macos, ios]
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
bundle install
cd ios && pod install && cd ..
- name: Archive
run: xcodebuild -workspace App.xcworkspace -scheme App -configuration Release archive
- name: Export IPA
run: xcodebuild -exportArchive -archivePath build/App.xcarchive -exportOptionsPlist ios/ExportOptions.plist -exportPath build
Для Flutter логика та же: тесты и общие шаги на Linux, iOS-упаковка на Mac runner. Пример можно сверить с Flutter iOS CI кейсом.
7) Операционный чеклист: не только быстро, но и стабильно
- Централизованный signing: сертификаты и профили под контролем.
- Отдельный пользователь runner: меньше «ручных» конфликтов.
- Точный retry: перезапускайте только сетевые/загрузочные шаги.
- Считайте полный TCO: железо, сопровождение и время команды.
Для оценки экономики: разбор TCO и цены.
8) Когда пора переходить на self-hosted
| Ситуация команды | Рекомендация | Почему |
|---|---|---|
| ≤ 1 iOS релиз в месяц | Можно остаться на hosted | Переход может не окупиться сразу |
| 2–4 релиза в месяц и постоянное ожидание CI | Запустить pilot self-hosted | Быстро видно ROI по времени |
| Еженедельные релизы / несколько приложений | Переходить на self-hosted | Максимум выигрыша по скорости и предсказуемости |
| Распределенная команда | Выбирать регион ближе к repo | Ниже задержки при checkout/upload |
Большая картина по инфраструктуре: война инфраструктуры вычислений ИИ.
9) FAQ (8 частых вопросов)
Q1: У нас одно iOS-приложение, self-hosted точно нужен?
Не всегда. Но если команда регулярно ждет CI, переход обычно оправдан.
Q2: Что оптимизировать в первую очередь?
CocoaPods и DerivedData. Это самый заметный быстрый эффект.
Q3: Сложно ли поддерживать self-hosted runner?
Старт требует времени, дальше при фиксированных версиях поддержка вполне рутинная.
Q4: Что делать с exit code 65?
Проверить версии Xcode/SDK, затем очистить DerivedData и повторить сборку.
Q5: Нужен ли Fastlane обязательно?
Нет. На первом этапе достаточно стабильной сборки и корректной выгрузки в TestFlight.
Q6: Лучше офисный Mac или облачный?
Для распределенной команды облачный Mac обычно проще и надежнее в эксплуатации.
Q7: Какие риски по безопасности?
Минимальные права, строгая работа с secrets, отдельный runner-user и аудит.
Q8: С чего начать практически?
Сделайте A/B за неделю: hosted vs self-hosted на вашем главном iOS pipeline и сравните фактическое время.