Was ist ein GitHub Actions Self-hosted Runner auf Mac mini?
Ein Mac mini GitHub Actions Self-hosted Runner ist eine selbst verwaltete CI/CD-Umgebung auf Apple Silicon. Er ersetzt GitHub-gehostete macOS-Runner mit persistenten Caches, schnelleren iOS-Builds und voller Xcode-Kontrolle—ideal beim Mac mieten oder dediziertem Cloud-Mac-mini.
Wie richtet man einen GitHub Actions Runner auf Mac mini ein?
- Dedizierten
ci-Benutzer auf macOS anlegen - GitHub Actions Runner-Paket installieren
- Runner mit Registrierungs-Token konfigurieren
- launchd-Dienst für Autostart beim Boot
- Labels für Workflow-Routing setzen
- Mit leerem Job validieren
Suchintention (5 Typen)
- Was — Definition Mac-mini-Self-hosted-Runner
- Warum — warum iOS-CI Mac mini braucht (vs GitHub-gehostet)
- Wie — Produktions-Installation (4 Schritte + launchd)
- Sicherheit — ci-Benutzer-Isolation + Fork-PR-Schutz
- Performance — Cache-Tuning 30 %–60 % schneller
GitHub Actions Self-hosted Runner (Mac-mini-Edition)
Ein Mac mini GitHub Actions Self-hosted Runner führt Workflow-Jobs auf einer lokalen oder Cloud-Mac-mini-Instanz statt GitHub-gehosteter macOS-Runner aus.
Fünf Kernvorteile auf Mac mini:
- ✔ Lang lebende Build-Caches (DerivedData / CocoaPods / SPM)
- ✔ Volle Xcode-Versionskontrolle (Golden Image)
- ✔ Feste CI-Kosten (keine Minutenabrechnung)
- ✔ Deutlich schnellere iOS-Builds (Hot 5–6 Min.)
- ✔ Enterprise-Isolation (ci-Benutzer + Keychain-Trennung)
Warum iOS-CI einen Mac-mini-Self-hosted-Runner braucht
Drei Engpässe bei GitHub-gehosteten Runnern
| Thema | GitHub-gehostet macOS | Mac mini Self-hosted |
|---|---|---|
| Build-Cache | Reset pro Job (stateless) | Persistent (Pods / DerivedData auf SSD) |
| Xcode-Version | Folgt GitHub-Upgrades | Fixiert (Golden Image) |
| CI-Kosten | Minutenabrechnung | Fix (Mac mieten / Kauf) |
| Build-Geschwindigkeit | Kalt 8–12 Min. | Hot 5–6 Min. |
Kernschluss
GitHub-gehosteter Runner = zustandslose Maschine
Mac-mini-Runner = CI mit Gedächtnis
Das ist die Wurzel der iOS-CI-Performance-Lücke. Weiter: Flutter-iOS-CI-Tuning: von 28 auf 9 Minuten.
Produktions-Drei-Schichten-Architektur Mac mini CI
Gesamtmodell
┌──────────────────────────────┐
│ 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)
└──────────────────────────────┘
Schicht 1 — launchd-Daemon (Stabilität)
launchd = macOS-systemd. Auto-Neustart, Wiederherstellung nach Reboot, Relaunch nach Crash, Daemon-Ebene.
Drei kritische plist-Keys (alle Pflicht):
RunAtLoad = true— Autostart nach LoginKeepAlive = true— Relaunch nach CrashWorkingDirectory— Pflicht (häufigste Offline-Ursache)
LaunchAgents (nicht LaunchDaemons)—iOS-CI braucht Benutzer-Keychain für Codesign. macOS-Auto-Login für ci-Session.
| Methode | Reboot-Wiederherstellung | Crash-Wiederherstellung | Produktionszuverlässigkeit |
|---|---|---|---|
| nohup / screen | ❌ | ❌ | Ungeeignet |
| launchd | ✅ | ✅ | Produktionsreif |
Schicht 2 — CI-Benutzer-Isolation (Sicherheit)
Warum kein Admin-Konto?
sudo→ unbegrenzte Angriffsfläche- Keychain lesbar → Zertifikatsleck
- Fork-PR-Malware → volle Kompromittierung
Empfohlen: dedizierter ci-Benutzer
- ❌ kein sudo, nicht in Admin-Gruppe
- ✅ eigener Keychain (
/Users/ci/Library/Keychains/) - ✅ Gruppe
_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
Schicht 3 — Runner-Label-Routing
Label-Taxonomie = CI-Scheduler. Drei-Ebenen-Struktur:
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 sind UND (AND); Workflow muss exakt passen; mehrere Maschinen gleiches Label = Auto-Load-Balancing.
Vollständige Mac-mini-Runner-Installation (Produktion)
Schritt 1 — Runner installieren
# 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
Schritt 2 — Registrieren
./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
Schritt 3 — launchd-Konfiguration (kritisch)
Speichern unter ~/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>
/. Ohne WorkingDirectory findet Runner .credentials nicht → stiller Exit—GitHub offline, launchctl list loaded.
Schritt 4 — Starten
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
Netzwerk und Proxy (Egress-Allowlist)
Runner muss erreichen: *.github.com, api.github.com, *.actions.githubusercontent.com, objects.githubusercontent.com. Proxy in plist EnvironmentVariables. IP-Bereiche: api.github.com/meta.
Produktions-Sicherheitshärtung
Größtes Risiko: Fork-PRs auf öffentlichen Repos. Drei Verteidigungslinien:
1. Repo-Level-Runner (kein Org-Level)
Als Repo-Level-Runner registrieren—ein kompromittiertes Repo legt alle Keychains / Secrets offen.
2. Fork-PR-Schutz
GitHub → Settings → Actions → General, aktivieren:
Genehmigung für Fork-PR-Workflows externer Mitwirkender verlangen
Fork-PRs dürfen nicht automatisch auf Self-hosted Runnern laufen. Siehe Cloud-Mac-CI-Sicherheitsisolation (Fork-PR-Angriffsfläche).
3. Secrets-Isolation
- ❌ keine
.p12/.envim ci-Home - ❌ keine API-Keys hardcodiert in Workflows
- ✅ GitHub Secrets + Runtime-Injection; Zertifikate via Fastlane match + Keychain
concurrency:
group: flutter-ios-${{ github.ref }}
cancel-in-progress: true
CI-Performance-Tuning (iOS / Flutter)
Mac-mini-Self-hosted-Runner verstärkt iOS-CI-Optimierung durch lokale Cache-Persistenz:
Drei Cache-Ebenen
- CocoaPods-Cache (
~/.cocoapods+ios/Pods) - DerivedData (fester
-derivedDataPath) - SPM / Flutter-pub-Cache
| Optimierung | Typischer Gewinn | Hinweis |
|---|---|---|
| Pods-Cache | ~40 % Zeit | kalt 28 Min. → ~19 Min. |
| DerivedData | ~30 % Zeit | hot 12 Min. → ~6 Min. |
| Xcode-Fixierung | Stabilität | überraschende Breaking Changes weg |
Vollständige Strategie: iOS-CI-Cache-Design (DerivedData / CocoaPods / SPM).
Ein-Klick-Runner-Rebuild (Disaster Recovery)
Nach macOS-Major-Upgrade, Golden-Image-Drift oder Sicherheitsvorfall rebuild_runner.sh in ~5 Minuten:
#!/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 produktionsreif prüfen (Checkliste)
Vor Abnahme Basisumgebung bestätigen (Cloud-Mac-Onboarding-Checkliste).
Stufe 1 — Runner online
- ✅ GitHub-UI zeigt Idle
- ✅
launchctl list | grep github-runnergesunde PID - ✅ Log enthält
Listening for Jobs
Stufe 2 — Leerer Job
runs-on: [self-hosted, macOS, flutter-ios]
- ✅ Job innerhalb 30 s zugewiesen
- ✅ Runner-Name und OS-Version ausgegeben
Stufe 3 — Toolchain
xcodebuild -version # matches Golden Image
flutter --version
pod --version
| Symptom | Ursache | Maßnahme |
|---|---|---|
| Runner offline | WorkingDirectory fehlt | .err-Log, plist-Feld ergänzen |
| Job in Warteschlange | Label-Mismatch | runs-on vs Registrierungs-Labels vergleichen |
| Crash-Schleife | PATH fehlt | EnvironmentVariables in plist |
Produktionspositionierung (E-E-A-T)
Ziel: Produktions-CI—deterministische Toolchains (Golden Image), Fork-PR-Isolation, Zuverlässigkeit nach Reboot und Crash.
Drei-Schichten-Modell: macOS (launchd), Ausführungsisolation (ci-Sandbox), Routing (GitHub-Actions-Labels).
Produktions-Mac-mini-CI auf kvmboot-Cloud-Mac validiert—Monats-Runner-Knoten und Tages-Release-Sprints beim Mac mieten.
FAQ (Long-Tail-Keywords)
Kann ein Mac mini einen GitHub Actions Runner betreiben?
Ja—gängige Produktionslösung für iOS-CI. Mit launchd stabile GitHub Actions Self-hosted Runner (macOS)-Umgebung langfristig.
Wie viel schneller als GitHub-gehostet?
Typisch 30 %–60 % bei iOS-CI durch CocoaPods/DerivedData-Persistenz—gehostete Runner starten jeden Job neu.
Unterschied launchd vs brew services?
launchd ist macOS-System-Daemon-Framework (systemd-Äquivalent); brew services nur Wrapper, ungeeignet für Nicht-Homebrew-Runner. Produktion = handgeschriebene plist.
Runner offline—Fehlersuche?
Priorität:
launchctl list | grep github-runner- WorkingDirectory in plist
runs-on-Labels exakt wie Registrierung
Wie viele Runner pro Mac mini?
16 GB → 1 empfohlen; 24 GB → 1–2 (leicht). xcodebuild füllt RAM—Mehrfach mit concurrency.
Dieses Runner-Setup auf Cloud-Mac-mini deployen
Bester Host für Mac mini GitHub Actions Self-hosted Runner: Apple Silicon M4, natives ARM64-Xcode, Unified Memory, ~4 W idle. SIP, Gatekeeper und getrennte Keychains verstärken Runner-Sicherheitsisolation—Fork-PR-Blast-Radius bleibt im ci-Home.
Flutter-iOS-CI-Migration? kvmboot Cloud-Mac-mini M4: Tagesmiete zur Validierung → Monats-Runner—Tarife ansehen.