GitLab Child/Parent-Pipelines fuer groessere Monorepos
AI generated
CI/CD
.yml
GitLab · CI/CD · DevOps
GitLab Child/Parent-Pipelines
fuer groessere Monorepos

Wenn ein Monorepo mehrere weitgehend unabhaengige Teilprojekte in einem einzigen Repository vereint, wird eine einzelne, monolithische .gitlab-ci.yml schnell unuebersichtlich und ineffizient. Parent-Child-Pipelines mit dem Keyword trigger loesen dieses Problem, indem sie jedem Teilprojekt eine eigene, unabhaengig ausfuehrbare Kind-Pipeline geben, die nur laeuft, wenn sich in ihrem Bereich tatsaechlich etwas geaendert hat.

17 Min. Lesezeit Parent-Child-Pipelines trigger Keyword Monorepo dynamische Pipelines

1. Warum eine monolithische Pipeline im Monorepo scheitert

Ein Monorepo buendelt mehrere Teilprojekte, etwa mehrere Microservices, ein Frontend und ein Backend oder mehrere Bibliotheken, in einem einzigen Git-Repository, was Code-Sharing und atomare Commits ueber Projektgrenzen hinweg erleichtert. Fuer die CI/CD-Pipeline entsteht daraus aber ein strukturelles Problem: Eine einzelne .gitlab-ci.yml, die alle Jobs fuer alle Teilprojekte enthaelt, wird mit wachsender Anzahl an Teilprojekten immer laenger und unuebersichtlicher, und ohne gezielte Steuerung laeuft bei jedem Commit die komplette Pipeline fuer alle Teilprojekte, selbst wenn sich nur eine einzige Zeile in einem einzigen Microservice geaendert hat.

Dieses Verhalten verschwendet nicht nur CI-Minuten, sondern verlangsamt auch die Feedback-Schleife fuer Entwickler erheblich, weil ein kleiner Fix in einem Teilprojekt trotzdem warten muss, bis Tests fuer voellig unbeteiligte Teilprojekte durchgelaufen sind. Mit wachsender Teamgroesse und zunehmender Anzahl an Teilprojekten wird eine monolithische Pipeline zudem zu einem gemeinsamen Aenderungspunkt, an dem sich mehrere Teams gegenseitig blockieren, weil jede Aenderung an der zentralen .gitlab-ci.yml potenziell alle Teilprojekte betrifft. Parent-Child-Pipelines loesen genau dieses Problem, indem sie die Verantwortung fuer jede Teilpipeline in eine eigene Datei auslagern, die unabhaengig vom Rest gepflegt und ausgeloest werden kann.

2. Wie trigger eine Kind-Pipeline startet

Das Keyword trigger definiert einen speziellen Job-Typ, der statt eines script-Blocks auf eine andere .gitlab-ci.yml-Datei verweist und diese als eigenstaendige Kind-Pipeline startet. Aus Sicht der Parent-Pipeline erscheint der trigger-Job wie ein normaler Job mit eigenem Status, der aber intern eine komplette zweite Pipeline mit eigenen Stages, eigenen Jobs und eigenem Pipeline-Status orchestriert. Die Kind-Pipeline laeuft dabei vollstaendig unabhaengig von den uebrigen Jobs der Parent-Pipeline und kann ihre eigenen Runner, ihre eigenen Variablen und ihre eigene Stage-Struktur haben, ohne dass sich beide Konfigurationen gegenseitig beeinflussen.

Kombiniert mit rules und changes laesst sich damit genau das Monorepo-Problem loesen: Ein trigger-Job pro Teilprojekt bekommt eine changes-Bedingung, die nur greift, wenn sich Dateien im entsprechenden Unterverzeichnis geaendert haben, sodass bei einem Commit, der nur den Payment-Service betrifft, ausschliesslich die Kind-Pipeline fuer Payment gestartet wird, waehrend die Kind-Pipelines fuer alle anderen Microservices komplett uebersprungen werden. Dieses selektive Ausloesen ist der zentrale Effizienzgewinn von Parent-Child-Pipelines gegenueber einer monolithischen Struktur.


trigger_payment_service:
  trigger:
    include: services/payment/.gitlab-ci.yml
    strategy: depend
  rules:
    - changes:
        - services/payment/**/*

trigger_frontend:
  trigger:
    include: services/frontend/.gitlab-ci.yml
    strategy: depend
  rules:
    - changes:
        - services/frontend/**/*

3. strategy: depend und der Pipeline-Status

Ohne zusaetzliche Konfiguration gilt ein trigger-Job standardmaessig als erfolgreich, sobald die Kind-Pipeline erfolgreich gestartet wurde, unabhaengig davon, ob die Kind-Pipeline selbst spaeter fehlschlaegt. Das ist fuer viele Anwendungsfaelle unerwuenscht, weil ein fehlgeschlagener Test in der Kind-Pipeline dann nicht automatisch die Parent-Pipeline als fehlgeschlagen markiert. Mit strategy: depend wird dieses Verhalten geaendert: Der trigger-Job wartet, bis die Kind-Pipeline vollstaendig abgeschlossen ist, und uebernimmt danach deren tatsaechlichen Erfolgs- oder Fehlerstatus, sodass die Parent-Pipeline den echten Zustand aller Kind-Pipelines korrekt widerspiegelt.

Diese Einstellung ist besonders wichtig, wenn nachgelagerte Jobs in der Parent-Pipeline von mehreren Kind-Pipelines abhaengen, etwa ein finaler Deployment-Job, der erst laufen soll, wenn alle betroffenen Teilprojekte erfolgreich getestet wurden. Ohne strategy: depend koennte dieser Deployment-Job faelschlicherweise starten, obwohl eine der Kind-Pipelines im Hintergrund noch laeuft oder sogar fehlgeschlagen ist. In der Praxis sollte strategy: depend deshalb der Standard fuer alle trigger-Jobs sein, bei denen der tatsaechliche Erfolg der Kind-Pipeline fuer die weitere Pipeline-Logik relevant ist, und nur in seltenen Faellen bewusst weggelassen werden, etwa fuer rein informative Kind-Pipelines ohne Blockierwirkung.

4. Dynamisch generierte Child-Pipeline-YAML als Artefakt

Neben statisch im Repository liegenden Kind-Pipeline-Dateien unterstuetzt GitLab auch dynamisch generierte Kind-Pipelines, bei denen ein vorgelagerter Job eine .gitlab-ci.yml-Datei zur Laufzeit erzeugt und als Artefakt bereitstellt, das dann als Grundlage fuer den trigger-Job dient. Das ist besonders wertvoll in Monorepos, in denen sich die Anzahl oder Struktur der Teilprojekte haeufig aendert, weil die Pipeline-Struktur nicht mehr fest im Code hinterlegt werden muss, sondern zur Laufzeit aus dem tatsaechlichen Repository-Zustand abgeleitet werden kann, etwa durch ein Skript, das alle Verzeichnisse mit einer package.json oder composer.json einliest und daraus automatisch einen Job pro Teilprojekt generiert.

Diese Technik wird oft mit dem Feld include: artifact kombiniert, das explizit angibt, dass die referenzierte Datei nicht statisch im Repository liegt, sondern als Artefakt eines vorherigen Jobs erzeugt wurde. Fuer sehr grosse Monorepos mit Dutzenden Teilprojekten ist dieser Ansatz oft die einzige praktikable Loesung, weil eine manuell gepflegte Liste aller Teilprojekte in der Parent-Pipeline schnell veraltet und fehleranfaellig wird, sobald neue Teilprojekte hinzukommen oder alte entfernt werden, waehrend eine generierte Pipeline automatisch den aktuellen Stand widerspiegelt.


generate_pipeline:
  stage: prepare
  script:
    - ./scripts/generate-child-pipeline.sh > generated-pipeline.yml
  artifacts:
    paths:
      - generated-pipeline.yml

trigger_generated:
  stage: trigger
  needs: [generate_pipeline]
  trigger:
    include:
      - artifact: generated-pipeline.yml
        job: generate_pipeline
    strategy: depend

5. Verschachtelungstiefe und Variablen-Weitergabe

GitLab erlaubt eine Verschachtelung von Kind-Pipelines bis zu einer festen Tiefe, wobei eine Parent-Pipeline eine Kind-Pipeline ausloesen kann, die wiederum eine eigene Kind-Pipeline ausloest. Diese sogenannten Multi-Project- oder mehrstufigen Pipelines sind hilfreich fuer sehr grosse Organisationen mit hierarchisch organisierten Teilprojekten, sollten aber mit Bedacht eingesetzt werden, weil jede zusaetzliche Verschachtelungsebene die Nachvollziehbarkeit erschwert und Debugging aufwendiger macht, wenn ein Fehler tief in einer verschachtelten Kind-Pipeline auftritt und erst durch mehrere Ebenen zurueckverfolgt werden muss.

Fuer die Weitergabe von Variablen an eine Kind-Pipeline bietet trigger das Unter-Keyword variables, mit dem gezielt Werte an die Kind-Pipeline uebergeben werden koennen, unabhaengig von den global definierten Variablen der Parent-Pipeline. Zusaetzlich kann mit forward gesteuert werden, ob Pipeline-Variablen und YAML-Variablen der Parent-Pipeline automatisch an die Kind-Pipeline weitergereicht werden sollen, was besonders bei dynamisch generierten Pipelines wichtig ist, um zu vermeiden, dass sensible oder projektspezifische Variablen ungewollt in Kind-Pipelines fuer andere Teilprojekte landen.


trigger_service_a:
  trigger:
    include: services/service-a/.gitlab-ci.yml
    strategy: depend
    forward:
      pipeline_variables: true
      yaml_variables: false
  variables:
    SERVICE_NAME: service-a
    DEPLOY_ENV: staging

6. Multi-Project-Pipelines als verwandtes Konzept

Neben Parent-Child-Pipelines innerhalb desselben Repositories unterstuetzt trigger auch das Ausloesen von Pipelines in einem komplett anderen GitLab-Projekt, sogenannte Multi-Project-Pipelines. Statt einer include-Datei wird dabei mit project: der Pfad zu einem anderen Projekt angegeben, wodurch ein Job in Projekt A eine Pipeline in Projekt B startet, etwa wenn ein zentrales Infrastruktur-Repository nach jedem erfolgreichen Build eines Anwendungsrepositories automatisch ein Deployment anstossen soll. Multi-Project-Pipelines sind konzeptionell verwandt mit Parent-Child-Pipelines, unterscheiden sich aber dadurch, dass die beiden beteiligten Pipelines in getrennten Projekten mit eigenen Berechtigungen und eigener Versionierung liegen.

Fuer Monorepos ist die trigger:include-Variante mit Kind-Pipelines im selben Repository meist die passendere Wahl, weil Aenderungen an Teilprojekt-Pipeline und Teilprojekt-Code in einem einzigen Commit landen und dieselbe Versionsgeschichte teilen. Multi-Project-Pipelines eignen sich dagegen besser fuer tatsaechlich getrennte Repositories, die organisatorisch oder aus Sicherheitsgruenden nicht zusammengelegt werden sollen, aber trotzdem eine koordinierte Pipeline-Ausfuehrung benoetigen, etwa zwischen einem separaten Infrastructure-as-Code-Repository und mehreren Anwendungsrepositories.

7. Praxis-Empfehlungen fuer den Aufbau

Fuer den Einstieg empfiehlt sich eine klare Verzeichnisstruktur, in der jedes Teilprojekt seine eigene .gitlab-ci.yml in seinem eigenen Unterverzeichnis pflegt, waehrend die Parent-Pipeline im Repository-Root nur noch aus einer Liste von trigger-Jobs mit passenden changes-Bedingungen besteht. Diese Trennung macht klar, wer fuer welche Pipeline-Logik verantwortlich ist, und erlaubt es Teams, ihre eigene Kind-Pipeline weitgehend unabhaengig von anderen Teams zu aendern, ohne Merge-Konflikte in einer gemeinsamen, riesigen .gitlab-ci.yml zu riskieren.

Wichtig ist ausserdem, gemeinsame Job-Definitionen, etwa fuer Linting oder Security-Scans, die in mehreren Teilprojekten identisch benoetigt werden, in eine zentrale, wiederverwendbare Datei auszulagern und ueber include in jede Kind-Pipeline einzubinden, statt sie in jedem Teilprojekt zu duplizieren. So bleibt die Struktur trotz mehrerer unabhaengiger Kind-Pipelines konsistent, und Aenderungen an gemeinsamen Standards muessen nur an einer Stelle gepflegt werden, was gerade bei vielen Teilprojekten den Unterschied zwischen wartbarer und chaotisch wachsender CI-Konfiguration ausmacht.

8. Typische Fallstricke bei Parent-Child-Pipelines

Ein haeufiger Fehler ist, strategy: depend zu vergessen und sich dann zu wundern, warum die Parent-Pipeline trotz fehlgeschlagener Kind-Pipeline als gruen angezeigt wird. Ein zweiter haeufiger Fehler betrifft changes-Bedingungen, die zu eng oder zu weit gefasst sind: Wird nur genau das Teilprojektverzeichnis in changes eingetragen, aber eine gemeinsam genutzte Bibliothek in einem anderen Verzeichnis geaendert, die das Teilprojekt tatsaechlich beeinflusst, laeuft die entsprechende Kind-Pipeline faelschlicherweise nicht, obwohl sie eigentlich laufen sollte, weil GitLab keine automatische Abhaengigkeitsanalyse ueber Verzeichnisgrenzen hinweg durchfuehrt.

Ein dritter Fallstrick betrifft die Sichtbarkeit von Fehlern: Da eine Kind-Pipeline in der Standardansicht der Parent-Pipeline nur als einzelner Job erscheint, muessen Entwickler aktiv in die Kind-Pipeline hineinklicken, um Details zu einem Fehlschlag zu sehen, was gerade fuer neue Teammitglieder zunaechst unintuitiv sein kann. Es lohnt sich deshalb, in der Job-Beschreibung des trigger-Jobs oder in der Team-Dokumentation kurz zu erklaeren, dass ein roter trigger-Job bedeutet, dass in der verlinkten Kind-Pipeline nachgeschaut werden muss, statt den Fehler direkt im Parent-Log zu suchen.

9. Fazit: Parent-Child-Pipelines als Skalierungswerkzeug

Parent-Child-Pipelines mit trigger sind das zentrale Werkzeug, um Monorepos mit mehreren Teilprojekten in GitLab CI beherrschbar zu halten, weil sie selektives Ausloesen ueber changes-Bedingungen, unabhaengige Kind-Pipeline-Konfigurationen und bei Bedarf dynamisch generierte Pipeline-Strukturen ermoeglichen. Richtig konfiguriert mit strategy: depend und klar getrennten Verantwortlichkeiten pro Teilprojekt skaliert dieser Ansatz auch fuer Monorepos mit Dutzenden Teilprojekten deutlich besser als eine einzelne monolithische Pipeline-Datei.

Die folgende Tabelle vergleicht die wichtigsten Merkmale von monolithischen Pipelines, statischen Parent-Child-Pipelines und dynamisch generierten Child-Pipelines als Entscheidungshilfe fuer die eigene Monorepo-Struktur.

Merkmal Monolithische Pipeline Statische Child-Pipeline Dynamische Child-Pipeline
Ausloesen bei Aenderung immer alle Jobs gezielt per changes-Bedingung gezielt, zur Laufzeit ermittelt
Pflegeaufwand bei neuen Teilprojekten zentrale Datei waechst neue Datei plus neuer trigger-Job automatisch aus Repository-Struktur
Fehlerstatus-Weitergabe direkt sichtbar nur mit strategy: depend korrekt nur mit strategy: depend korrekt
Geeignet fuer kleine, einfache Repos Monorepos mit stabiler Struktur Monorepos mit haeufig wechselnder Struktur

Mironsoft

CI/CD-Pipelines, Zero-Downtime-Deployments und Release-Automatisierung

Deployments, die ohne Ausfallzeit und ohne Nervenkitzel laufen?

Wir prüfen bestehende GitLab-Pipelines auf fragile Deployment-Schritte und fehlende Absicherung und bauen daraus einen Release-Prozess mit Zero-Downtime-Deployments, automatisierten Checks und einem Rollback, dem ihr im Ernstfall vertrauen könnt.

Pipeline-Review

Bestehende .gitlab-ci.yml auf Fragilität, fehlende Stages und Sicherheitslücken prüfen.

Zero-Downtime-Deployment

Symlink-Releases, Health-Checks und Rollback-Strategien für Magento-Shops aufbauen.

CI/CD-Automatisierung

Tests, Security-Scans und Deployments zu einer zuverlässigen Pipeline verbinden.

10. Zusammenfassung

Child/Parent-Pipelines: Das Wichtigste auf einen Blick

Kernidee

trigger startet eine eigenstaendige Kind-Pipeline pro Teilprojekt, statt alle Jobs in einer monolithischen Datei zu buendeln.

Selektives Ausloesen

changes-Bedingungen pro trigger-Job sorgen dafuer, dass nur tatsaechlich betroffene Teilpipelines laufen.

Kritische Einstellung

strategy: depend sorgt dafuer, dass die Parent-Pipeline den echten Erfolgs- oder Fehlerstatus der Kind-Pipeline uebernimmt.

Fuer sehr grosse Monorepos

Dynamisch generierte Child-Pipeline-YAML als Artefakt vermeidet manuell gepflegte, schnell veraltende Trigger-Listen.

11. FAQ: Child/Parent-Pipelines: Das Wichtigste auf einen Blick

1Was ist der Unterschied zwischen Parent-Child-Pipelines und Multi-Project-Pipelines?
Parent-Child-Pipelines loesen Kind-Pipelines im selben Repository und Projekt aus, meist ueber eine include-Datei im Repository. Multi-Project-Pipelines loesen dagegen eine Pipeline in einem komplett anderen GitLab-Projekt aus, ueber das project-Feld im trigger-Keyword.
2Warum wird meine Parent-Pipeline trotz fehlgeschlagener Kind-Pipeline als erfolgreich angezeigt?
Ohne strategy: depend gilt ein trigger-Job bereits als erfolgreich, sobald die Kind-Pipeline gestartet wurde, unabhaengig von deren spaeterem Ergebnis. Mit strategy: depend wartet der trigger-Job auf den Abschluss und uebernimmt den tatsaechlichen Status der Kind-Pipeline.
3Wie starte ich eine Kind-Pipeline nur, wenn sich das zugehoerige Teilprojekt geaendert hat?
Der trigger-Job bekommt eine rules-Bedingung mit einer changes-Klausel, die auf das Verzeichnis des Teilprojekts zeigt. Nur wenn sich Dateien in diesem Pfad seit dem letzten Vergleichspunkt geaendert haben, wird die Kind-Pipeline tatsaechlich ausgeloest.
4Was bedeutet eine dynamisch generierte Child-Pipeline?
Ein vorgelagerter Job erzeugt zur Laufzeit eine .gitlab-ci.yml-Datei, etwa basierend auf der aktuellen Repository-Struktur, und stellt sie als Artefakt bereit. Der trigger-Job referenziert diese Datei dann ueber include mit artifact statt einer statischen Datei im Repository.
5Wie tief koennen Kind-Pipelines verschachtelt werden?
GitLab erlaubt eine Verschachtelung von Kind-Pipelines bis zu einer festen Tiefe von mehreren Ebenen. In der Praxis sollte diese Verschachtelung sparsam eingesetzt werden, weil jede zusaetzliche Ebene die Nachvollziehbarkeit und das Debugging erschwert.
6Werden Variablen automatisch an eine Kind-Pipeline weitergegeben?
Das haengt von der forward-Konfiguration im trigger-Job ab. Ueber pipeline_variables und yaml_variables laesst sich gezielt steuern, ob Variablen der Parent-Pipeline automatisch an die Kind-Pipeline weitergereicht werden, zusaetzlich zu explizit gesetzten variables.
7Kann eine Kind-Pipeline eigene Runner und eigene Variablen haben?
Ja, eine Kind-Pipeline ist eine vollstaendig eigenstaendige Pipeline mit eigenen Stages, eigenen Jobs, eigenen Runner-Zuweisungen und eigenen Variablen, die unabhaengig von der Parent-Pipeline konfiguriert werden.
8Was passiert, wenn eine changes-Bedingung eine gemeinsam genutzte Bibliothek nicht erfasst?
Wenn eine geteilte Bibliothek ausserhalb des ueberwachten Teilprojektverzeichnisses liegt, erkennt GitLab die Abhaengigkeit nicht automatisch. Die betroffene Kind-Pipeline laeuft dann trotz relevanter Aenderung nicht, sofern das Bibliotheksverzeichnis nicht explizit in die changes-Liste aufgenommen wird.
9Lohnen sich Parent-Child-Pipelines auch fuer kleine Repositories?
Bei kleinen Repositories mit nur ein oder zwei Teilprojekten ist der Zusatzaufwand meist nicht gerechtfertigt. Der Nutzen wird ab mehreren, klar abgrenzbaren Teilprojekten sichtbar, insbesondere wenn diese unterschiedlich haeufig geaendert werden.
10Wie sehe ich den Status einer Kind-Pipeline in der GitLab-Oberflaeche?
In der Parent-Pipeline-Ansicht erscheint der trigger-Job mit einem eigenen Status-Icon, das anklickbar ist und direkt zur zugehoerigen Kind-Pipeline mit allen ihren eigenen Jobs und Stages fuehrt.