Fehlerbild: Ihre iOS-Pipeline wartet, die Signaturumgebung ist unklar oder ein gemeinsam genutzter Runner gefährdet vertrauliche Variablen.
Schnellste Lösung: Setzen Sie die GitLab Runner macOS-Buildmaschine als dedizierten Knoten für vertrauenswürdige Projekte ein, testen Sie zunächst einen einzelnen Knoten und erweitern Sie erst anhand realer Wartezeiten und Parallelität.
Diese Anleitung ist für Plattform- und IT-Verantwortliche gedacht, die iOS-Projekte in GitLab CI/CD überführen. Sie ist ebenso relevant, wenn Sie Signaturzertifikate, Netzwerkzugriffe und die Beschaffung eigener oder gemieteter Mac-Knoten verantworten.
Vor dem ersten Terminal: Die Grenzen des Buildknotens
Eine macOS-Buildmaschine ist kein neutraler allgemeiner Server. Bei einem Shell Executor laufen Jobs mit den Berechtigungen des Runner-Benutzers. GitLab weist ausdrücklich darauf hin, dass Shell Runner nur für vertrauenswürdige Builds eingesetzt werden sollten, weil ein Auftrag unter Umständen auf Dateien anderer Projekte oder auf Geheimnisse des Hosts zugreifen kann. GitLab-Dokumentation zu den Sicherheitsrisiken des Shell Executors
Definieren Sie deshalb vor der Installation drei Grenzen:
- Vertrauensgrenze: Welche Repositories dürfen diesen Host verwenden?
- Signaturgrenze: Darf der Knoten nur testen und archivieren oder auch veröffentlichen?
- Betriebsgrenze: Wird der Mac nur während der Arbeitszeit genutzt oder muss er nach einem Neustart unbeaufsichtigt wieder verfügbar sein?
Für eine erste produktionsnahe Prüfung ist ein einzelner dedizierter Runner sinnvoll. Er beantwortet konkrete Fragen: Wie lange dauert ein echter Build? Wie oft warten Jobs? Funktionieren Keychain, Simulator und Artefaktarchivierung nach einem Neustart? Die Teamgröße allein liefert dafür keine belastbare Kapazitätszahl.
Die typische Fehlentscheidung
Ein Unternehmen registriert einen Runner auf Gruppen- oder Instanzebene, aktiviert nicht markierte Jobs und lässt anschließend viele unterschiedliche Repositories auf demselben Shell-Host laufen. Das wirkt zunächst effizient. Mit jedem zusätzlichen Projekt wachsen jedoch Abhängigkeiten, Cache-Reste, lokale Arbeitsverzeichnisse und die Zahl der Personen, die indirekt Einfluss auf den Host nehmen können.
Starten Sie stattdessen mit einem Projekt-Runner oder einem eng begrenzten Gruppen-Runner. GitLab unterscheidet Projekt-, Gruppen- und Instanz-Runner; diese Ebenen bestimmen, für welche Projekte ein Runner verfügbar ist. GitLab-Dokumentation zu Runner-Ebenen und Registrierung
Achtung: Ein geschützter Runner ersetzt keine Trennung der Projekte. Er verhindert bestimmte Job-Zuordnungen, schafft aber keine vollständige Prozess- oder Dateisystemisolation.
Erste Stunde: macOS und Laufzeitkonto vorbereiten
GitLab Runner unterstützt macOS auf Apple Silicon und Intel-x86-64-Systemen. Unter macOS läuft der Runner laut GitLab nicht als systemweiter LaunchDaemon, sondern als Benutzerprozess über einen LaunchAgent. Er startet beim Anmelden des konfigurierten Benutzers und endet beim Abmelden. GitLab-Anleitung zur macOS-Installation
Das ist für iOS-Builds entscheidend. Der Benutzerkontext ermöglicht den Zugriff auf die Benutzer-Keychain, die grafische Sitzung und den iOS Simulator. Gleichzeitig entsteht eine betriebliche Abhängigkeit: Ein Host kann technisch erreichbar sein und trotzdem keine Jobs annehmen, wenn die erforderliche Benutzersitzung fehlt.
Vorbereitung in fünf Schritten
Eigenes Laufzeitkonto anlegen
Verwenden Sie kein persönliches Entwicklerkonto. Das Konto sollte ausschließlich für GitLab Runner, Xcode und die vorgesehenen Buildwerkzeuge verwendet werden. Gewähren Sie keine unnötigen Administratorrechte.
Zugriffskanäle festlegen
Legen Sie fest, ob die Erstinstallation über eine lokale grafische Sitzung, SSH oder eine verwaltete Fernwartung erfolgt. Für die Installation des macOS-Dienstes verlangt GitLab eine angemeldete grafische Sitzung; eine reine SSH-Sitzung kann beim Bootstrap des LaunchAgent scheitern.
Netzwerk beschränken
Erlauben Sie nur die erforderlichen Verbindungen zu GitLab, Paketquellen, Apple-Diensten und internen Artefakt- oder Secretsystemen. VNC oder eine andere Fernwartung sollte nicht allgemein aus dem Internet erreichbar sein.
Festplattenverschlüsselung prüfen
Aktivieren und dokumentieren Sie FileVault beziehungsweise die in der Organisation vorgesehene Verschlüsselungsrichtlinie. Apple beschreibt FileVault als Schutz gegen den Zugriff auf Daten vor der Anmeldung; der Wiederherstellungsschlüssel muss außerhalb des verschlüsselten Startvolumes verwahrt werden. Apple-Dokumentation zu FileVault-Wiederherstellungsoptionen
Betriebszustand dokumentieren
Notieren Sie macOS-Version, Architektur, Xcode-Version, aktive Entwicklerumgebung, Ruby- oder Swift-Abhängigkeiten sowie Paketmanager. Diese Basis gehört in die Inventarisierung und nicht nur in den Kopf eines einzelnen Administrators.
Installieren Sie anschließend Xcode und führen Sie den ersten Start sowie die Lizenz- und Komponenteninitialisierung durch. Die GitLab-Anleitung nennt dafür xcodebuild -runFirstLaunch und die Auswahl des aktiven Entwicklerverzeichnisses über xcode-select. GitLab-Anleitung zur Konfiguration von Xcode auf macOS
Ein notwendiges Grundgerüst sieht beispielsweise so aus:
sudo xcodebuild -runFirstLaunch
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
xcodebuild -version
gitlab-runner --version
Die konkreten Versionen sollten Sie nicht blind aus einem Beispiel übernehmen. Entscheidend ist, dass Ihre Pipeline dieselbe Xcode-Version verwendet wie der getestete Build und dass Änderungen an Xcode als geplante Infrastrukturänderung behandelt werden.
Zweiter Schritt: Executor und Aufgabenrouting festlegen
Für native iOS- und macOS-Builds ist der Shell Executor der naheliegende Weg, weil Xcode und die macOS-Werkzeuge direkt auf dem Host ausgeführt werden. GitLab beschreibt den Shell Executor auch in der macOS-Einrichtung als passenden Executor für diese Builds. GitLab-Anleitung für macOS Runner
Das bedeutet jedoch nicht, dass Shell die sicherste allgemeine Wahl ist. Der Executor bietet keine starke Isolation zwischen Jobs. Ein Projekt, das beliebige Skripte ausführen darf, kann unter Umständen auf lokale Dateien, installierte Werkzeuge, Cache-Inhalte oder Umgebungsvariablen zugreifen.
Für die Entscheidung gilt:
- Wenn nur vertrauenswürdige, intern kontrollierte Repositories gebaut werden: Shell Executor auf einem dedizierten macOS-Knoten ist vertretbar.
- Wenn externe Beiträge oder unzuverlässige Skripte gebaut werden: Verwenden Sie keinen gemeinsam genutzten Shell Runner mit Signaturmaterial.
- Wenn stärkere Isolation erforderlich ist: Prüfen Sie eine Architektur mit kurzlebigen virtuellen Maschinen oder einem geeigneten isolierten Executor. Verfügbarkeit, Bereitstellungszeit, Xcode-Installation und Signaturzugriff müssen separat bewertet werden.
Registrierung und Routing
Registrieren Sie den Runner auf der kleinstmöglichen Ebene. Nutzen Sie aktuelle Runner-Authentifizierungstoken statt veralteter Registrierungstoken, sofern Ihre GitLab-Version und Ihr Administrationsprozess dies unterstützen. GitLab beschreibt den neuen Registrierungsablauf mit Authentifizierungstoken in seiner Dokumentation. GitLab-Dokumentation zum neuen Registrierungsablauf
Ein minimales Registrierungsgerüst kann so aussehen:
gitlab-runner register \
--url "https://gitlab.example.com" \
--token "$RUNNER_AUTHENTICATION_TOKEN" \
--executor "shell" \
--description "ios-build-macos" \
--tag-list "macos,ios"
Die Tags macos und ios müssen anschließend im jeweiligen Job verwendet werden. GitLab nutzt Tags zur Zuordnung von Jobs zu Runnern; sie sind nicht dasselbe wie Git-Tags. GitLab-Dokumentation zur Runner-Konfiguration
Verwenden Sie zusätzlich geschützte Branches und Tags für alle Aufgaben, die Distribution-Zertifikate, App-Store-Profile oder produktive Veröffentlichungsschritte benötigen. Ein allgemeiner Testjob darf den Releaseknoten nicht allein dadurch erreichen, dass er das passende Betriebssystem anfordert.
Dritter Schritt: Build, Cache und Signatur als geschlossene Kette prüfen
Beginnen Sie nicht mit der vollständigen Release-Pipeline. Erstellen Sie zunächst eine kleine Pipeline, die vier Dinge beweist:
- Der Quellcode wird auf dem erwarteten Host ausgecheckt.
- Xcode kann das Projekt ohne manuelle Eingabe bauen.
- Tests und Ergebnisse werden an GitLab zurückgegeben.
- Ein definiertes Artefakt wird archiviert.
Beispiel:
stages:
- build
- test
- archive
variables:
LANG: "en_US.UTF-8"
build_ios:
stage: build
tags:
- macos
- ios
script:
- xcodebuild -version
- xcodebuild -scheme "$SCHEME" -destination "$DESTINATION" build
test_ios:
stage: test
tags:
- macos
- ios
script:
- xcodebuild test -scheme "$SCHEME" -destination "$DESTINATION"
archive_ios:
stage: archive
tags:
- macos
- ios
script:
- xcodebuild archive -scheme "$SCHEME" -archivePath build/App.xcarchive
artifacts:
paths:
- build/App.xcarchive
Die Platzhalter für Scheme und Destination sollten aus geschützten Variablen oder aus der Projektkonfiguration kommen. Speichern Sie keine Zertifikate, privaten Schlüssel oder Passwörter direkt in der Repository-Datei.
Signaturmaterial richtig trennen
Apple beschreibt eine digitale Signieridentität als Kombination aus Zertifikat und privatem Schlüssel. Ein exportiertes PKCS#12-Objekt wird in die Benutzer-Keychain importiert; Provisioning Profiles werden separat verwaltet und müssen zur App-ID, zum Zertifikat und zum vorgesehenen Zweck passen. Apple-Dokumentation zu Teamsignaturzertifikaten
Für Unternehmen ist deshalb eine Zwei-Knoten-Logik oft sinnvoll:
- Testknoten: kein Distribution-Privatkey, nur Build- und Testabhängigkeiten.
- Releaseknoten: geschützter Runner, geschützter Branch oder geschütztes Tag, restriktive Variablen und gesonderte Freigabe.
Die Signatur sollte innerhalb eines kontrollierten Jobabschnitts erfolgen:
- temporäre Keychain erstellen oder eine dedizierte Login-Keychain verwenden;
- Zertifikat und privaten Schlüssel aus geschützten Variablen oder einem Secretsystem importieren;
- Provisioning Profile nur für die Laufzeit des Jobs bereitstellen;
- nach dem Export Keychain, Profile und temporäre Dateien entfernen;
- Logausgaben auf Zertifikatsnamen, Pfade und Token prüfen.
Apple weist außerdem darauf hin, dass automatische Signierung Provisioning Profiles bei der Archivierung aktualisieren kann, während manuelle Signierung eine gezielte Auswahl von Profil und Zertifikat erfordert. Apple-Dokumentation zu Signierung und Distribution Für reproduzierbare Releaseprozesse ist eine bewusst dokumentierte manuelle oder zentral gesteuerte Signaturstrategie meist leichter zu auditieren.
Vierter Schritt: Neustart, Keychain und Fernzugriff testen
Die wichtigste Besonderheit der GitLab Runner macOS-Buildmaschine ist nicht die Registrierung, sondern der Wiederanlauf. Weil der Runner als LaunchAgent im Benutzerkontext ausgeführt wird, müssen Sie nach einem Neustart mehr prüfen als nur den Status in der GitLab-Oberfläche.
Testen Sie in dieser Reihenfolge:
- Mac neu starten.
- Automatische Anmeldung oder den vorgesehenen Anmeldeprozess ausführen.
- Prüfen, ob der LaunchAgent geladen wurde.
gitlab-runner statusausführen.- Einen ungefährlichen Testjob starten.
- Zugriff auf Keychain und Simulator prüfen.
- Einen absichtlich abgebrochenen Job erneut ausführen.
- Fernwartung und Notfallzugang testen.
GitLab nennt die automatische Anmeldung als Voraussetzung dafür, den Runner nach einem Neustart verfügbar zu halten. Das muss mit Ihrer Sicherheitsrichtlinie vereinbar sein. Wenn automatische Anmeldung nicht zulässig ist, brauchen Sie einen dokumentierten manuellen oder verwalteten Entsperrprozess.
Erfahrung aus der Betriebsplanung: „Online“ im GitLab-Portal beweist nicht, dass Xcode signieren, der Simulator starten oder die verschlüsselte Platte nach einem Neustart entsperrt werden kann. Diese Funktionen müssen als eigene Akzeptanztests behandelt werden.
Prüfen Sie zusätzlich Arbeitsverzeichnisse und Caches. Ein Shell Runner kann Projektdateien auf dem Host hinterlassen. Legen Sie deshalb fest, wann Arbeitsverzeichnisse gelöscht werden, wie lange Logs und Artefakte aufbewahrt werden und welche Cache-Inhalte projektübergreifend verwendet werden dürfen.
Mehrere Projekte auf einer macOS-Buildmaschine
Mehrere Projekte können technisch denselben macOS Runner verwenden. Für produktive Signaturumgebungen ist diese Entscheidung jedoch nur dann vertretbar, wenn alle Projekte derselben Vertrauensgrenze unterliegen und die Berechtigungen, Variablen sowie Bereinigungsregeln gemeinsam verwaltet werden.
Eine gemeinsame Testmaschine kann sinnvoll sein, wenn:
- die Repositories derselben Organisation gehören;
- alle Pipelines intern geprüft werden;
- kein Projekt fremde Pull Requests mit beliebigen Shell-Befehlen ausführt;
- keine dauerhaften Release-Schlüssel auf dem Testknoten liegen;
- Arbeitsverzeichnisse und Caches nach jedem Lauf kontrolliert bereinigt werden.
Sie sollten Projekte trennen, wenn unterschiedliche Kunden, Sicherheitsklassen, Xcode-Versionen oder Veröffentlichungspflichten betroffen sind. Besonders kritisch ist die Kombination aus gemeinsamem Shell Runner und dauerhaft hinterlegtem Distribution-Privatkey.
Wann ist der erste Knoten ausreichend und wann brauchen Sie mehrere?
Erhöhen Sie die Knotenzahl nicht, weil mehr Entwickler eingestellt wurden. Messen Sie stattdessen:
- durchschnittliche und maximale Queue-Zeit;
- Build-Dauer nach Pipeline-Typ;
- Anzahl paralleler Jobs;
- Wiederholungs- und Fehlerrate;
- Speicher- und Festplattenwachstum;
- Wartezeit durch Xcode-Versionen oder Signaturjobs;
- geplante Wartungsfenster.
Die Kapazitätsformel sollte zunächst als Messmodell dienen:
benötigte Knoten
= Spitzenlast paralleler Jobs
× durchschnittliche Jobdauer
÷ zulässiges Zeitfenster
Das Ergebnis ist keine exakte Gerätezahl. Es zeigt, welche Messwerte Ihnen noch fehlen. Bei stark schwankender Last kann ein zusätzlicher Reserveknoten wirtschaftlicher sein als eine dauerhaft große Flotte. Bei mehreren Xcode-Versionen sollten Sie die Knoten nach Version gruppieren, statt jede Maschine mit allen Versionen zu beladen.
Entscheidungsbedingungen für die nächste Ausbaustufe
- Wenn die Queue-Zeit in Spitzen regelmäßig über Ihr internes Ziel steigt: Fügen Sie einen zweiten Knoten mit identischem Xcode- und Abhängigkeitsstand hinzu.
- Wenn nur Releasejobs warten, normale Tests aber frei laufen: Trennen Sie Release- und Testknoten, statt die gesamte Flotte zu vergrößern.
- Wenn mehrere Xcode-Versionen parallel erforderlich sind: Bilden Sie je Version eine eigene Runner-Gruppe mit eindeutigen Tags.
- Wenn die Last nur an wenigen Tagen stark ansteigt: Prüfen Sie eine periodische Miete oder einen temporären Remote-Mac.
- Wenn dauerhaft hohe, planbare Last besteht und physischer Zugriff notwendig ist: Ein gekaufter, fest betriebener Mac kann langfristig besser passen.
- Wenn Sie keinen lokalen Betrieb, keine Ersatzgeräte und keine sichere Fernwartung organisieren können: Starten Sie den Piloten mit einem verwalteten Remote-Mac von KVMNODE.
Für eine zusätzliche Einordnung der Hardwarebeschaffung können Sie die Mac-mini-Optionen für Unternehmen mit Ihrer internen Beschaffung vergleichen. Einen breiteren Überblick über verfügbare Remote-Mac-Szenarien finden Sie außerdem in der deutschen KVMNODE-Übersicht. Maßgeblich bleiben jedoch die reale Builddauer, die Queue-Zeit und der Aufwand für Betrieb und Wiederherstellung.
Drei Tabellen für die Produktionsentscheidung
| Entscheidungspunkt | Dedizierter Shell Runner | Isolierter oder kurzlebiger Runner | Empfehlung für den Piloten |
|---|---|---|---|
| Native Xcode- und Simulator-Nutzung | Direkt auf macOS | Abhängig vom Image und der Sitzung | Dedizierter macOS-Knoten |
| Isolation zwischen Projekten | Begrenzt | Höher, abhängig von der Architektur | Nur vertrauenswürdige Projekte |
| Signaturzugriff | Möglich, aber sensibel | Besser trennbar | Releaseknoten separat |
| Betriebsaufwand | Niedrig bis mittel | Mittel bis hoch | Mit einem Knoten beginnen |
| Geeignet für unbekannten Code | Nein | Eher geeignet, wenn korrekt isoliert | Nicht auf dem Shell-Knoten zulassen |
| Betriebsmodell | Typische Kostenvariablen | Vorteile | Nachteile |
|---|---|---|---|
| Eigener Mac | Anschaffung, Garantie, Strom, Standort, Ersatzgerät, Administration | Kontrolle und planbare Verfügbarkeit | Kapitalbindung, Wartung und Ausfallrisiko |
| Periodisch gemieteter Remote-Mac | Mietzeitraum, Fernzugriff, Datenverkehr, Support, mögliche Zusatzoptionen | Schneller Pilot, flexible Kapazität | Abhängigkeit von Netzwerk und Anbieter |
| Gemischte Flotte | Dauerlast plus temporäre Knoten | Gute Anpassung an Spitzen | Mehrere Betriebsmodelle und Richtlinien |
| Große permanente Flotte | Geräte, Ersatzkapazität, Updates, Monitoring | Hohe Grundkapazität | Risiko von Leerlauf und veralteten Xcode-Ständen |
| Prüfkriterium | Go | No-Go |
|---|---|---|
| Build | Reproduzierbarer Build mit festgelegter Xcode-Version | Manuelle Eingriffe erforderlich |
| Signatur | Releasematerial nur auf geschütztem Knoten | Zertifikat liegt in allgemeiner Pipeline-Variable |
| Routing | Tags und geschützte Branches greifen | Unmarkierte Jobs erreichen den Host |
| Wiederanlauf | Neustart, Sitzung und Testjob funktionieren | Runner erscheint online, kann aber nicht bauen |
| Bereinigung | Arbeitsverzeichnis und temporäre Schlüssel werden entfernt | Projekt- oder Signaturreste bleiben zurück |
| Kapazität | Queue- und Builddaten werden aufgezeichnet | Knotenzahl basiert nur auf Entwicklerzahl |
Für die Kostenplanung tragen Sie reale Werte ein, statt allgemeine Marktpreise zu übernehmen:
Jahreskosten eigener Mac
= Anschaffung
+ Wartung
+ Strom und Standort
+ Ersatzkapazität
+ Administrationszeit
Jahreskosten Remote-Mac
= Wochen- oder Monatsmiete
+ Supportoptionen
+ Netzwerk- und Speicherbedarf
+ zusätzliche Spitzenknoten
Go-/No-Go-Entscheidung für den Produktionsstart
Vor dem produktiven Einsatz sollte der verantwortliche Bereich mindestens diese Nachweise ablegen:
- Runner-Ebene und erlaubte Projekte;
- Architektur: Apple Silicon oder Intel;
- macOS- und Xcode-Baseline;
- Shell-Executor-Risikoanalyse;
- Netzwerkfreigaben und Fernwartung;
- FileVault- und Wiederherstellungskonzept;
- Signaturknoten und Berechtigungen;
- Schutz von Branches, Tags und Variablen;
- Cache- und Bereinigungsregeln;
- Neustart- und Notfalltest;
- Queue- und Builddaten aus dem Piloten;
- Entscheidungskriterium für einen zweiten Knoten.
Die Abnahme ist bestanden, wenn ein realer Build ohne manuelle Korrektur durchläuft, die Signaturgrenze nachweisbar funktioniert und ein Neustart nicht zu einem unbemerkten Produktionsausfall führt. Ein Runner, der nur im Normalzustand funktioniert, ist noch keine belastbare CI/CD-Infrastruktur.
Wenn Sie derzeit einzelne gekaufte Macs an Entwickler oder einen manuell gepflegten Mac mini als Ausweichlösung verteilen, liegen die Schwächen meist in der Kapitalbindung, der uneinheitlichen Xcode-Konfiguration, fehlender Ersatzkapazität und dem Aufwand für Fernwartung. Ein gemieteter Remote-Mac von KVMNODE ist deshalb vor allem für den Pilotbetrieb, schwankende Last und Teams ohne eigene Mac-Betriebsbereitschaft interessant. Für dauerhaft hohe und planbare Last oder Anforderungen an physische Geräteanschlüsse kann ein eigener Mac weiterhin die bessere Wahl sein.
Starten Sie mit einer echten Pipeline, nicht mit einer theoretischen Flottenplanung. Sobald Sie Spitzenparallelität, Xcode-Versionen, Releasehäufigkeit und Wiederherstellungszeit kennen, können Sie bei KVMNODE einen Remote-Mac für einen definierten Zeitraum einplanen und anhand der Messdaten über weitere Knoten oder eine längere Mietdauer entscheiden.