Qu'est-ce qu'un runner auto-hébergé GitHub Actions sur Mac mini ?
Un runner auto-hébergé Mac mini GitHub Actions est un environnement CI/CD géré par vous sur Apple Silicon. Il remplace les runners macOS GitHub avec caches persistants, builds iOS plus rapides et contrôle total de Xcode—idéal pour louer un Mac ou un Mac mini cloud dédié.
Comment installer un runner GitHub Actions sur Mac mini ?
- Créer un utilisateur
cidédié sur macOS - Installer le paquet GitHub Actions runner
- Configurer avec un jeton d'enregistrement
- Service launchd pour démarrage au boot
- Labels pour le routage des workflows
- Valider avec un job vide
Intentions de recherche (5 types)
- Quoi — définition du runner auto-hébergé Mac mini
- Pourquoi — pourquoi l'iOS CI exige Mac mini (vs GitHub hébergé)
- Comment — installation production (4 étapes + launchd)
- Sécurité — isolation ci + protection fork PR
- Performance — optimisation cache 30 %–60 %
Runner auto-hébergé GitHub Actions (édition Mac mini)
Un runner auto-hébergé Mac mini GitHub Actions exécute les jobs workflow sur une instance Mac mini locale ou Mac cloud au lieu des runners macOS GitHub.
Cinq avantages clés sur Mac mini :
- ✔ Caches de build durables (DerivedData / CocoaPods / SPM)
- ✔ Version Xcode maîtrisée (Golden Image)
- ✔ Coût CI fixe (pas de facturation à la minute)
- ✔ Builds iOS nettement plus rapides (chaud 5–6 min)
- ✔ Isolation entreprise (utilisateur ci + Keychain séparé)
Pourquoi l'iOS CI doit utiliser un runner auto-hébergé Mac mini
Trois goulots des runners GitHub hébergés
| Problème | macOS GitHub hébergé | Mac mini auto-hébergé |
|---|---|---|
| Cache build | Reset à chaque job | Persistant (Pods / DerivedData SSD) |
| Version Xcode | Suit les mises à jour GitHub | Figée (Golden Image) |
| Coût CI | À la minute | Fixe (louer un Mac / achat) |
| Vitesse build | Froid 8–12 min | Chaud 5–6 min |
Conclusion
Runner GitHub hébergé = machine sans état
Runner Mac mini = CI avec mémoire
Cause racine des écarts iOS CI. Suite : Optimisation Flutter iOS CI : de 28 à 9 minutes.
Architecture production trois couches Mac mini CI
Modèle global
┌──────────────────────────────┐
│ 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)
└──────────────────────────────┘
Couche 1 — démon launchd (stabilité)
launchd = systemd macOS. Redémarrage auto, reprise après reboot, relance après crash, niveau démon.
Trois clés plist obligatoires :
RunAtLoad = true— démarrage après loginKeepAlive = true— relance après crashWorkingDirectory— obligatoire (cause n°1 offline)
Utiliser LaunchAgents (pas LaunchDaemons)—l'iOS CI a besoin du Keychain utilisateur pour la signature. Auto-login macOS pour la session ci.
| Méthode | Reprise reboot | Reprise crash | Fiabilité prod |
|---|---|---|---|
| nohup / screen | ❌ | ❌ | Inadapté |
| launchd | ✅ | ✅ | Production |
Couche 2 — isolation utilisateur CI
Pourquoi pas un compte admin ?
sudo→ surface d'attaque illimitée- Keychain lisible → fuite certificats
- fork PR malveillant → compromission totale
Recommandé : utilisateur ci dédié
- ❌ pas sudo, hors groupe admin
- ✅ Keychain séparé (
/Users/ci/Library/Keychains/) - ✅ groupe
_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
Couche 3 — routage par labels
Taxonomie de labels = planificateur CI. Structure à trois niveaux :
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 │
└──────────────┘ └───────────────────┘ └──────────────┘
Labels en ET (AND) ; workflow doit correspondre exactement ; plusieurs machines même label = équilibrage auto.
Installation complète runner Mac mini (production)
Étape 1 — Installer le 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
Étape 2 — Enregistrer
./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
Étape 3 — Config launchd (critique)
Enregistrer dans ~/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>
/ par défaut. Sans WorkingDirectory, pas de .credentials → sortie silencieuse—GitHub offline, launchctl list loaded.
Étape 4 — Démarrer
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
Réseau et proxy (liste blanche sortante)
Le runner doit joindre *.github.com, api.github.com, *.actions.githubusercontent.com, objects.githubusercontent.com. Proxy dans plist EnvironmentVariables. Plages IP : api.github.com/meta.
Durcissement sécurité production
Risque majeur : fork PR sur dépôts publics. Trois lignes de défense :
1. Runner au niveau dépôt (pas organisation)
Enregistrer au niveau dépôt pour éviter la propagation latérale—un repo compromis expose tous les Keychains / Secrets.
2. Protection fork PR
GitHub → Settings → Actions → General, activer :
Exiger l'approbation pour les workflows fork des collaborateurs externes
Les fork PR ne doivent pas s'exécuter auto sur runners auto-hébergés. Voir isolation sécurité CI Mac cloud (surface fork PR).
3. Isolation des secrets
- ❌ pas de
.p12/.envdans le home ci - ❌ pas de clés API en dur dans les workflows
- ✅ GitHub Secrets + injection runtime ; certificats via Fastlane match + Keychain
concurrency:
group: flutter-ios-${{ github.ref }}
cancel-in-progress: true
Optimisation performance CI (iOS / Flutter)
Le runner auto-hébergé Mac mini amplifie l'optimisation iOS CI via caches locaux persistants :
Trois couches de cache
- Cache CocoaPods (
~/.cocoapods+ios/Pods) - DerivedData (chemin
-derivedDataPathfixe) - Cache SPM / Flutter pub
| Optimisation | Gain typique | Notes |
|---|---|---|
| Cache Pods | ~40 % temps | froid 28 min → ~19 min |
| DerivedData | ~30 % temps | chaud 12 min → ~6 min |
| Xcode figé | stabilité | supprime changements cassants |
Stratégie complète : Design cache iOS CI (DerivedData / CocoaPods / SPM).
Reconstruction runner en un clic (DR)
Après upgrade macOS majeur, dérive Golden Image ou incident sécurité, rebuild_runner.sh en ~5 minutes :
#!/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."
Vérifier que le runner est production-ready
Avant acceptation, confirmer l'environnement de base (checklist onboarding Mac cloud).
Niveau 1 — Runner en ligne
- ✅ UI GitHub Idle
- ✅
launchctl list | grep github-runnerPID sain - ✅ log contient
Listening for Jobs
Niveau 2 — Job vide
runs-on: [self-hosted, macOS, flutter-ios]
- ✅ job assigné sous 30 s
- ✅ nom runner et version OS affichés
Niveau 3 — Toolchain
xcodebuild -version # matches Golden Image
flutter --version
pod --version
| Symptôme | Cause | Action |
|---|---|---|
| Runner offline | WorkingDirectory absent | log .err, ajouter champ plist |
| Job en file | labels non concordants | comparer runs-on et labels |
| Boucle crash | PATH manquant | ajouter EnvironmentVariables au plist |
Positionnement production (E-E-A-T)
Conçu pour la CI production : toolchains déterministes (Golden Image), isolation fork PR, fiabilité après reboot et crash.
Modèle trois couches : macOS (launchd), isolation (sandbox ci), routage (labels GitHub Actions).
Implémentation Mac mini CI validée sur Mac cloud kvmboot—nœuds runner mensuels et machines sprint journalières quand vous louez un Mac.
FAQ (mots-clés longue traîne)
Un Mac mini peut-il exécuter un runner GitHub Actions ?
Oui—configuration production courante pour l'iOS CI. Avec launchd, environnement runner auto-hébergé GitHub Actions (macOS) stable long terme.
Combien plus rapide qu'un runner GitHub hébergé ?
Typiquement 30 %–60 % sur iOS CI grâce à la persistance CocoaPods / DerivedData—les runners hébergés repartent à zéro chaque job.
Différence launchd vs brew services ?
launchd est le framework démon système macOS (équivalent systemd) ; brew services est un wrapper inadapté aux runners non-Homebrew. Production = plist manuel.
Runner offline : comment diagnostiquer ?
Par priorité :
launchctl list | grep github-runner- WorkingDirectory dans le plist
- labels
runs-onidentiques à l'enregistrement
Combien de runners sur un Mac mini ?
16 Go → 1 recommandé ; 24 Go → 1–2 (léger). xcodebuild sature la RAM—multi-instances avec concurrency.
Déployer ce runner sur un Mac mini cloud
Meilleur hôte pour un runner auto-hébergé Mac mini GitHub Actions : Apple Silicon M4, Xcode ARM64 natif, mémoire unifiée, ~4 W idle. SIP, Gatekeeper et Keychains séparés renforcent l'isolation sécurité runner—rayon d'explosion fork PR limité au home ci.
Migration Flutter iOS CI ? kvmboot Mac mini cloud M4 : location journalière → nœud runner mensuel—voir les offres.