Dein Ausgangspunkt
Wenn du einen dedizierten Cloud Mac mini M4 bei KVMFLUX mietest, erhältst du root-äquivalente Verwaltungsrechte auf echter Apple-Hardware: 16GB Unified Memory, 256GB SSD, macOS vorinstalliert, zugänglich per SSH und VNC. Es gibt kein Teilen und keine Virtualisierung, sodass xcodebuild den vollen M4 sieht und sich die Secure Enclave genauso verhält wie auf deiner eigenen Maschine.
Wähle die Region, die deinem Artefakt-Speicher am nächsten liegt, nicht deinem Team. Ein Runner kommuniziert weit häufiger mit Git-Hosting und CDNs als irgendein Mensch tatsächlich mit ihm interagiert — verfügbar in Singapur, Japan, Südkorea, Hongkong, US-Ost und US-West.
Schritt 1 — SSH zuerst absichern, dann alles andere
Die Maschine wird mit aktivierter Passwortanmeldung ausgeliefert, um den ersten Zugang zu erleichtern. Das solltest du in der ersten Sitzung beenden: erst den Schlüssel hinterlegen, dann Passwörter deaktivieren.
ssh-keygen -t ed25519 -f ~/.ssh/kvmflux_ci -C "ci-runner"
ssh-copy-id -i ~/.ssh/kvmflux_ci.pub admin@<YOUR_MAC_HOST>
sudo tee -a /etc/ssh/sshd_config <<'EOF'
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitRootLogin no
EOF
sudo launchctl kickstart -k system/com.openssh.sshd
Für einen CI-Knoten sind zwei weitere Einstellungen entscheidend: verhindern, dass die Maschine einschläft, und sicherstellen, dass Hintergrunddienste nicht pausieren, wenn kein Display angeschlossen ist.
sudo pmset -a sleep 0 displaysleep 0 disksleep 0
sudo systemsetup -setrestartfreeze on
Behalte VNC als Rückweg. Manche Xcode-Dialoge — Lizenzbestätigungen, Berechtigungen beim ersten Simulatorstart — erscheinen nur in der grafischen Oberfläche. Du brauchst einen Weg hinein, der auch funktioniert, wenn die SSH-Konfiguration schiefgeht.
Schritt 2 — Xcode-Toolchain installieren
Überspringe den App Store. xcodes installiert eine bestimmte Xcode-Version nicht-interaktiv, genau das, was ein kopfloser Knoten braucht. Installiere zuerst Homebrew, dann die Toolchain.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
brew install xcodesorg/made/xcodes aria2
xcodes install 16.2 --experimental-unxip
sudo xcodes select 16.2
sudo xcodebuild -license accept
sudo xcodebuild -runFirstLaunch
Bestätige die Zielplattformen, die du tatsächlich baust. Wenn die Pipeline Simulator-Tests ausführt, lade die Runtimes jetzt herunter — nicht erst beim ersten Job.
xcodebuild -downloadPlatform iOS
xcrun simctl list runtimes
xcodebuild -version
Füge die Tools hinzu, die mobile Pipelines üblicherweise brauchen: fastlane für Lanes und Signierung, git-lfs, falls dein Repository binäre Assets enthält.
brew install fastlane git-lfs jq
git lfs install --system
Schritt 3 — Die Maschine als Runner registrieren
GitHub Actions, GitLab und Buildkite folgen alle dem gleichen Muster: einen Agenten herunterladen, ihm ein begrenztes Token geben, ihn als Dienst laufen lassen. So sieht das für die GitHub-Actions-Variante auf Apple Silicon aus.
mkdir ~/actions-runner && cd ~/actions-runner
curl -o runner.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.321.0/actions-runner-osx-arm64-2.321.0.tar.gz
tar xzf runner.tar.gz
./config.sh --url https://github.com/your-org/your-app \
--token <REGISTRATION_TOKEN> \
--labels macos,arm64,m4 --unattended
./svc.sh install && ./svc.sh start
Die Installation über svc.sh bindet den Runner in launchd ein, sodass er nach einem Neustart auch ohne angemeldete Desktop-Sitzung weiterläuft. Nutze Labels, um Jobs gezielt zu routen:
jobs:
build:
runs-on: [self-hosted, macos, m4]
steps:
- uses: actions/checkout@v4
- run: xcodebuild -scheme App -destination \
'platform=iOS Simulator,name=iPhone 16' test
Registrierungstokens laufen nach einer Stunde ab und sind nur einmal nutzbar — das ist beabsichtigt. Die dauerhaften Zugangsdaten des Runners liegen in der Datei .credentials im Runner-Verzeichnis, also halte dieses Benutzerkonto "langweilig": keine persönlichen SSH-Schlüssel, keine offenen Browsersitzungen.
Schritt 4 — Ein Schlüsselbund, den CI selbst entsperren kann
Signierung ist der Punkt, an dem die meisten selbstverwalteten Mac-Setups scheitern. Die Lösung ist ein dedizierter Schlüsselbund, den deine Lane erstellt, entsperrt und danach wegwirft — so bekommt der Login-Schlüsselbund niemals einen Dialog und Zugangsdaten sickern nicht zwischen Jobs durch.
KEYCHAIN=ci.keychain-db
security create-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN
security set-keychain-settings -lut 3600 $KEYCHAIN
security unlock-keychain -p "$KEYCHAIN_PASS" $KEYCHAIN
security import dist.p12 -k $KEYCHAIN -P "$P12_PASS" \
-T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple: \
-s -k "$KEYCHAIN_PASS" $KEYCHAIN
security list-keychains -d user -s $KEYCHAIN login.keychain-db
Die Zeile mit set-key-partition-list wird häufig übersehen — ohne sie hängt codesign und wartet auf einen grafischen Passwortdialog, der niemals erscheint. Wenn du fastlane nutzt, automatisiert match zusammen mit einem privaten Zertifikats-Repository diesen gesamten Ablauf.
Caching: Ergebnisse auf der Festplatte behalten
Der Hauptgrund, warum eine dedizierte Maschine besser ist als ein flüchtiger Runner, ist genau das: Zustand bleibt erhalten. Nutze das, statt bei jedem Job das halbe Internet neu herunterzuladen:
- DerivedData — Zeige mit
-derivedDataPath ~/ci-cache/ddauf einen festen Pfad; inkrementelle Build-Zeiten sinken oft von Minuten auf Sekunden. - Swift-Pakete — Setze
-clonedSourcePackagesDirPath ~/ci-cache/spm, damit die Abhängigkeitsauflösung bestehende Checkouts zwischen Jobs wiederverwendet. - CocoaPods und Homebrew — Beide cachen standardmäßig im Home-Verzeichnis des Runner-Nutzers; räume nur nicht zwischen Builds den Arbeitsbereich weg.
Kalkuliere realistisch mit dem Speicherplatz. Auf einer 256GB SSD belegen Xcode plus Runtimes rund 40GB, und der Cache eines aktiven Projekts wächst schnell auf 60–80GB. Räume planmäßig auf, nicht erst wenn es Probleme gibt:
find ~/ci-cache/dd -maxdepth 1 -mtime +14 -exec rm -rf {} +
xcrun simctl delete unavailable
df -h /
Wenn dein Projekt umfangreiche Assets mitbringt oder mehrere Xcode-Versionen parallel benötigt, kostet das Add-on Zusätzliche SSD +1TB nur $11.7/Monat — deutlich günstiger, als beim Release volle Festplatten zu debuggen.
Parallelität: Wie viele Jobs verträgt ein M4?
Ein M4 mit 16GB verarbeitet einen anspruchsvollen Job gut: ein vollständiger sauberer Build plus Simulator-Testsuite nutzt alle Kerne aus. Zwei simulatorbasierte Jobs gleichzeitig funktionieren für kleine Apps noch, aber beide verlangsamen sich, sobald der Speicherdruck steigt.
Unsere Faustregel nach mehreren Monaten Pipeline-Betrieb:
- Für Build-plus-Test-Workloads ist ein Runner-Prozess mit jeweils einem Job der sicherste Standard.
- Teile Lint, Unit-Tests und UI-Tests erst in separate Jobs auf, wenn eine zweite Maschine hinzukommt — sie auf derselben Maschine in eine Warteschlange zu stellen, bringt nur zusätzlichen Overhead.
- Nächtliche Jobs sind kostenlose Rechenleistung: Plane Abhängigkeitsprüfungen und Screenshot-Batches außerhalb der Arbeitszeiten der jeweiligen Zeitzone.
Wenn Warteschlangenzeiten zum Engpass werden, skaliert ein weiterer gemieteter Knoten linear — registriere ihn einfach mit denselben Labels, der Scheduler übernimmt die Lastverteilung. Die Rechnung zwischen Tages- und Monatsknoten ist ein eigenes Thema, das wir in unserer Kostenanalyse zu Mietzeiträumen durchgerechnet haben; verwandte Workflows findest du auch im Überblick der Einsatzszenarien.
Die gesamte Einrichtung, komprimiert
- SSH nur mit Schlüssel, Ruhezustand deaktiviert, VNC als Rückweg behalten.
- Xcode mit
xcodesinstallieren, Lizenz akzeptieren, Runtimes im Voraus herunterladen. - Den Runner als
launchd-Dienst mit aussagekräftigen Labels registrieren. - Dedizierter CI-Schlüsselbund mit korrekt gesetzter Partitionsliste.
- Caches persistent halten und regelmäßig aufräumen.
Der gesamte Vorgang dauert praktisch unter einer Stunde und ergibt einen Build-Knoten, um den sich das Team keine Sorgen mehr machen muss — genau darum geht es.
Auf echter Hardware ausprobieren
Jeder Befehl oben wurde auf genau der Art Maschine geschrieben und verifiziert, die wir vermieten. Miete eine, folge den Schritten, kündige, wenn es nicht passt — in beiden Fällen bleibt keine Hardware-Rechnung übrig.
Dedizierte Hardware, Abrechnung in USD, jederzeit kündbar.