Что такое self-hosted runner GitHub Actions на Mac mini?
Mac mini GitHub Actions self-hosted runner — среда CI/CD под вашим управлением на Apple Silicon. Заменяет macOS runner GitHub: постоянные кэши, быстрые iOS-сборки, полный контроль Xcode—идеально при аренде Mac или выделенном cloud Mac mini.
Как развернуть GitHub Actions runner на Mac mini?
- Создать выделенного пользователя
ciв macOS - Установить пакет GitHub Actions runner
- Настроить runner токеном регистрации
- Служба launchd для автозапуска
- Метки для маршрутизации workflow
- Проверить пустым Job
Поисковые намерения (5 типов)
- Что — определение self-hosted runner на Mac mini
- Зачем — почему iOS CI нужен Mac mini (vs GitHub-hosted)
- Как — продакшен-установка (4 шага + launchd)
- Безопасность — изоляция ci + защита fork PR
- Производительность — кэш даёт ускорение 30%–60%
Self-hosted runner GitHub Actions (версия Mac mini)
Mac mini GitHub Actions self-hosted runner выполняет workflow jobs на локальном или облачном Mac mini вместо macOS runner GitHub.
Пять ключевых преимуществ на Mac mini:
- ✔ Долгоживущие кэши сборки (DerivedData / CocoaPods / SPM)
- ✔ Полный контроль версии Xcode (Golden Image)
- ✔ Фиксированная стоимость CI (без поминутной оплаты)
- ✔ Значительно быстрее iOS-сборки (горячие 5–6 мин)
- ✔ Корпоративная изоляция (ci + отдельный Keychain)
Почему iOS CI должен использовать Mac mini self-hosted runner
Три узких места GitHub-hosted runner
| Проблема | GitHub-hosted macOS | Mac mini self-hosted |
|---|---|---|
| Кэш сборки | Сброс каждый job (stateless) | Постоянный (Pods / DerivedData на SSD) |
| Версия Xcode | Следует обновлениям GitHub | Зафиксирована (Golden Image) |
| Стоимость CI | Поминутная | Фикс (аренда Mac / покупка) |
| Скорость сборки | Холодный старт 8–12 мин | Горячая 5–6 мин |
Вывод
GitHub-hosted runner = машина без памяти
Mac mini runner = CI с памятью
Суть разрыва производительности iOS CI. Далее: Оптимизация Flutter iOS CI: с 28 до 9 минут.
Продакшен трёхслойная архитектура Mac mini CI
Общая модель
┌──────────────────────────────┐
│ Layer 1: launchd daemon │ ← reliability (auto-restart / crash recovery)
├──────────────────────────────┤
│ Layer 2: ci user isolation │ ← security (Keychain / permission boundary)
├──────────────────────────────┤
│ Layer 3: label routing │ ← maintainability (workflow → Runner)
└──────────────────────────────┘
Слой 1 — демон launchd (стабильность)
launchd = systemd macOS. Автоперезапуск, восстановление после reboot, relaunch после crash, уровень демона.
Три обязательных ключа plist:
RunAtLoad = true— автозапуск после входаKeepAlive = true— перезапуск после сбояWorkingDirectory— обязателен (главная причина offline)
Использовать LaunchAgents (не LaunchDaemons)—iOS CI нужен пользовательский Keychain для подписи. Автовход macOS для сессии ci.
| Способ | После reboot | После crash | Надёжность prod |
|---|---|---|---|
| nohup / screen | ❌ | ❌ | Не подходит |
| launchd | ✅ | ✅ | Продакшен |
Слой 2 — изоляция CI-пользователя
Почему не учётка администратора?
sudo→ неограниченная поверхность атаки- Keychain читается → утечка сертификатов
- fork PR со злым скриптом → полная компрометация
Рекомендация: выделенный ci
- ❌ без sudo, вне группы admin
- ✅ отдельный Keychain (
/Users/ci/Library/Keychains/) - ✅ группа
_developer(xcodebuild / simctl)
sudo dscl . -create /Users/ci UserShell /bin/zsh
sudo dscl . -create /Users/ci RealName "CI Runner"
sudo dscl . -create /Users/ci UniqueID 505
sudo dscl . -create /Users/ci PrimaryGroupID 20
sudo dscl . -create /Users/ci NFSHomeDirectory /Users/ci
sudo createhomedir -c -u ci
sudo passwd ci
sudo dscl . -append /Groups/_developer GroupMembership ci
Слой 3 — маршрутизация меток runner
Таксономия меток = планировщик CI. Трёхуровневая структура:
runs-on: [self-hosted, macOS, ARM64, flutter-ios, xcode-16, m4]
┌──────────────┐ ┌───────────────────┐ ┌──────────────┐
│ Platform │ │ Workload │ │ Hardware │
│ self-hosted │ │ flutter-ios │ │ m4, 16gb │
│ macOS, ARM64 │ │ xcode-16 │ │ region:tokyo │
└──────────────┘ └───────────────────┘ └──────────────┘
Метки — логическое И (AND); workflow должен совпасть полностью; несколько машин с одной меткой = балансировка.
Полная установка Mac mini runner (продакшен)
Шаг 1 — Установка runner
# Run as ci user
mkdir -p ~/actions-runner && cd ~/actions-runner
curl -fsSL -O https://github.com/actions/runner/releases/download/v2.316.1/actions-runner-osx-arm64-2.316.1.tar.gz
tar xzf actions-runner-osx-arm64-2.316.1.tar.gz
Шаг 2 — Регистрация
./config.sh \
--url https://github.com/your-org/your-repo \
--token YOUR_REGISTRATION_TOKEN \
--name "$(hostname -s)" \
--labels "self-hosted,macOS,ARM64,flutter-ios,xcode-16,m4,16gb" \
--work _work \
--replace \
--unattended
Шаг 3 — Конфиг launchd (критично)
Сохранить в ~/Library/LaunchAgents/com.kvmboot.github-runner.plist:
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0"><dict>
<key>Label</key><string>com.kvmboot.github-runner</string>
<key>ProgramArguments</key>
<array><string>/Users/ci/actions-runner/run.sh</string></array>
<key>WorkingDirectory</key><string>/Users/ci/actions-runner</string>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string>
</dict>
<key>StandardOutPath</key><string>/Users/ci/Library/Logs/github-runner.log</string>
<key>StandardErrorPath</key><string>/Users/ci/Library/Logs/github-runner.err</string>
</dict></plist>
/. Без WorkingDirectory runner не находит .credentials и тихо выходит—GitHub offline, launchctl list loaded.
Шаг 4 — Запуск
launchctl load ~/Library/LaunchAgents/com.kvmboot.github-runner.plist
launchctl list | grep github-runner
tail -f ~/Library/Logs/github-runner.log # expect: Listening for Jobs
Сеть и прокси (egress allowlist)
Runner должен достигать *.github.com, api.github.com, *.actions.githubusercontent.com, objects.githubusercontent.com. Прокси в plist EnvironmentVariables. Диапазоны IP: api.github.com/meta.
Усиление безопасности продакшен
Главный риск — fork PR в публичных репозиториях. Три линии обороны:
1. Runner уровня репозитория (не организации)
Регистрировать на уровне репозитория—компрометация одного repo открывает все Keychain / Secrets.
2. Защита fork PR
GitHub → Settings → Actions → General, включить:
Требовать одобрение workflow fork внешних соавторов
fork PR не должны автоматически выполняться на self-hosted runner. См. изоляция безопасности cloud Mac CI (поверхность fork PR).
3. Изоляция secrets
- ❌ не хранить
.p12/.envв home ci - ❌ не хардкодить API-ключи в workflow
- ✅ GitHub Secrets + runtime injection; сертификаты через Fastlane match + Keychain
concurrency:
group: flutter-ios-${{ github.ref }}
cancel-in-progress: true
Оптимизация производительности CI (iOS / Flutter)
Self-hosted runner на Mac mini усиливает оптимизацию iOS CI за счёт локального постоянного кэша:
Три слоя кэша
- Кэш CocoaPods (
~/.cocoapods+ios/Pods) - DerivedData (фиксированный
-derivedDataPath) - Кэш SPM / Flutter pub
| Оптимизация | Типичный выигрыш | Примечание |
|---|---|---|
| Кэш Pods | ~40% времени | холодная 28 мин → ~19 мин |
| DerivedData | ~30% времени | горячая 12 мин → ~6 мин |
| Фиксация Xcode | стабильность | убирает неожиданные breaking changes |
Полная стратегия: дизайн кэша iOS CI (DerivedData / CocoaPods / SPM).
Пересборка runner в один клик (DR)
После major-апгрейда macOS, дрейфа Golden Image или инцидента безопасности — rebuild_runner.sh за ~5 минут:
#!/usr/bin/env zsh
set -euo pipefail
CI_USER="ci"
PLIST_DEST="/Users/$CI_USER/Library/LaunchAgents/com.kvmboot.github-runner.plist"
sudo -u "$CI_USER" launchctl unload "$PLIST_DEST" 2>/dev/null || true
sudo -u "$CI_USER" bash -c "cd /Users/$CI_USER/actions-runner && ./config.sh remove --token \$(gh api -X POST /repos/your-org/your-repo/actions/runners/remove-token --jq '.token') 2>/dev/null || true"
sudo -u "$CI_USER" zsh /Users/$CI_USER/scripts/setup_runner.sh
sudo -u "$CI_USER" launchctl load "$PLIST_DEST"
echo "[OK] Runner rebuilt."
Проверка готовности runner к продакшену
Перед приёмкой подтвердите базовую среду (чеклист онбординга cloud Mac).
Уровень 1 — Runner online
- ✅ GitHub UI показывает Idle
- ✅
launchctl list | grep github-runner— здоровый PID - ✅ в логе
Listening for Jobs
Уровень 2 — Пустой job
runs-on: [self-hosted, macOS, flutter-ios]
- ✅ job назначен за 30 с
- ✅ вывод имени runner и версии ОС
Уровень 3 — Toolchain
xcodebuild -version # matches Golden Image
flutter --version
pod --version
| Симптом | Причина | Действие |
|---|---|---|
| Runner offline | WorkingDirectory не задан | лог .err, добавить поле plist |
| Job в очереди | несовпадение меток | сравнить runs-on и метки регистрации |
| Цикл crash | нет PATH | добавить EnvironmentVariables в plist |
Позиционирование продакшен (E-E-A-T)
Дизайн для продакшен CI: детерминированные toolchain (Golden Image), изоляция fork PR, устойчивость к reboot и crash.
Трёхслойная модель: macOS (launchd), изоляция выполнения (sandbox ci), маршрутизация (метки GitHub Actions).
Продакшен-Mac mini CI проверен на облачном Mac kvmboot—месячные runner-узлы и дневные release-машины при аренде Mac.
FAQ (длинный хвост)
Может ли Mac mini запускать GitHub Actions runner?
Да—одна из типичных продакшен-схем для iOS CI. С launchd стабильная среда GitHub Actions self-hosted runner (macOS) на длительный срок.
Насколько быстрее self-hosted vs GitHub-hosted?
Обычно 30%–60% для iOS CI за счёт CocoaPods/DerivedData—hosted каждый job с чистой средой.
Разница launchd и brew services?
launchd — системный демон macOS (аналог systemd); brew services — обёртка, не для non-Homebrew runner. Продакшен — plist вручную.
Runner offline — как искать?
По приоритету:
launchctl list | grep github-runner- WorkingDirectory в plist
- метки
runs-onточно как при регистрации
Сколько runner на одном Mac mini?
16 ГБ → 1 рекомендуется; 24 ГБ → 1–2 (лёгкие). xcodebuild забивает RAM—несколько с concurrency.
Развернуть этот runner на облачном Mac mini
Лучший хост для Mac mini GitHub Actions self-hosted runner — Apple Silicon M4: нативный ARM64 Xcode, unified memory, ~4 В в простое. SIP, Gatekeeper и отдельные Keychain усиливают изоляцию безопасности runner—радиус fork PR ограничен home ci.
Миграция Flutter iOS CI? kvmboot cloud Mac mini M4: посуточная проверка → месячный runner—смотреть тарифы.