Veröffentlicht am: 9. April 2026

11 Minuten Lesezeit

5 GitLab-Pipeline-Muster für komplexe Engineering-Herausforderungen

Wie Parent-Child-Pipelines, DAG-Execution, MR-Pipelines und CI/CD Components komplexe Delivery-Probleme lösen – von Monorepos bis zur governed Plattform.

Abschnitt 1: Das Modell verstehen

Für Engineering-Leads und Entscheidungsträger: Konzept, Anwendungsfälle und Architekturprinzipien. Konfigurationsdetails folgen in Abschnitt 2.

Die meisten CI/CD-Werkzeuge können einen Build ausführen und ein Deployment anstoßen. Der Unterschied zeigt sich erst dann, wenn die Delivery-Anforderungen komplexer werden: ein Monorepo mit einem Dutzend Services, Microservices über mehrere Repositories verteilt, Deployments in Dutzende von Umgebungen gleichzeitig – oder ein Platform-Team, das organisationsweite Standards durchsetzen will, ohne dabei zum Engpass zu werden.

GitLabs Pipeline-Modell wurde für genau diese Komplexität entwickelt. Parent-Child-Pipelines, DAG-Execution, dynamische Pipeline-Generierung, Multi-Project-Trigger, Merge-Request-Pipelines mit Merged-Results-Verarbeitung und CI/CD Components lösen jeweils eine eigene Klasse von Problemen. Da sich diese Bausteine kombinieren lassen, erschließt das vollständige Modell mehr als nur kürzere Pipeline-Laufzeiten.

Dieser Artikel beschreibt die fünf Muster, bei denen das Modell seine Stärken deutlich zeigt – jeweils zugeordnet zu einem konkreten Engineering-Szenario. Konfigurationen und Implementierungsdetails folgen in Abschnitt 2.

1. Monorepos: Parent-Child-Pipelines und DAG-Execution

Das Problem: Ein Monorepo enthält Frontend, Backend und Dokumentation. Jeder Commit löst einen vollständigen Rebuild aller Komponenten aus – auch wenn sich nur eine README-Datei geändert hat.

GitLab kombiniert zwei sich ergänzende Mechanismen: Parent-Child-Pipelines ermöglichen es einer übergeordneten Pipeline, isolierte Child-Pipelines zu starten. DAG-Execution via needs bricht die starre Stage-Reihenfolge auf und startet Jobs, sobald ihre Abhängigkeiten abgeschlossen sind – nicht erst, wenn alle Jobs einer Stage fertig sind.

Eine Parent-Pipeline erkennt, welche Teile des Repos sich geändert haben, und löst ausschließlich die betroffenen Child-Pipelines aus. Jeder Service verwaltet seine eigene Pipeline-Konfiguration; Änderungen in einem Service können keine anderen beeinflussen. Damit bleibt die Komplexität beherrschbar, während das Repository und das Team wachsen.

Einen technischen Aspekt gilt es dabei zu kennen: Wenn mehrere Dateien an einen einzelnen trigger: include:-Block übergeben werden, fusioniert GitLab sie zu einer einzigen Child-Pipeline-Konfiguration. Jobs aus diesen Dateien teilen denselben Pipeline-Kontext und können sich gegenseitig per needs: referenzieren – das ist die Voraussetzung für die DAG-Optimierung. Werden die Dateien stattdessen auf separate Trigger-Jobs aufgeteilt, entsteht jeweils eine isolierte Pipeline, und dateiübergreifende needs:-Referenzen funktionieren nicht.

In großen Monorepos lassen sich Pipeline-Laufzeiten durch DAG-Execution deutlich reduzieren, da Jobs nicht mehr auf unabhängige Arbeitsschritte in derselben Stage warten.

2. Microservices: Cross-Repo-Pipelines über mehrere Projekte

Das Problem: Frontend und Backend leben in separaten Repositories. Wenn das Frontend-Team eine Änderung ausliefert, ist nicht erkennbar, ob sie die Backend-Integration beeinträchtigt – und umgekehrt.

Multi-Project-Pipelines ermöglichen es, aus einem Projekt heraus eine Pipeline in einem anderen Projekt auszulösen und auf das Ergebnis zu warten. Das auslösende Projekt sieht die verknüpfte Downstream-Pipeline direkt in seiner eigenen Pipeline-Ansicht.

In der Praxis erstellt die Frontend-Pipeline ein API-Contract-Artifact und veröffentlicht es, bevor die Backend-Pipeline ausgelöst wird. Das Backend ruft dieses Artifact über die Jobs API ab und validiert es, bevor weitere Schritte erlaubt sind. Wird eine Breaking Change erkannt, schlägt die Backend-Pipeline fehl – und mit ihr die Frontend-Pipeline. Probleme, die bisher erst in der Produktion sichtbar wurden, werden damit im Pipeline-Prozess abgefangen. Die Abhängigkeit zwischen Services wird sichtbar, nachvollziehbar und aktiv verwaltbar.

Cross-project pipelinesCross-project pipelines Cross-project pipelines

3. Multi-Tenant/Matrix-Deployments: Dynamische Child-Pipelines

Das Problem: Dieselbe Anwendung wird in 15 Kundenumgebungen, drei Cloud-Regionen oder den Stages Dev/Staging/Prod deployed. Manuelle Anpassungen je Umgebung führen zu Konfigurationsdrift. Eine separate Pipeline pro Umgebung ist von Anfang an nicht wartbar.

Dynamische Child-Pipelines generieren die Pipeline-Struktur zur Laufzeit. Ein Job führt ein Skript aus, das eine YAML-Datei erzeugt – und diese YAML-Datei wird zur Pipeline für den nächsten Schritt. Die Pipeline-Struktur selbst wird damit zu Daten.

Das Generierungsskript iteriert über eine ENVIRONMENTS-Variable, statt jede Umgebung fest zu kodieren. Eine neue Umgebung lässt sich durch Anpassen der Variable hinzufügen – ohne Änderungen an der Pipeline-Konfiguration selbst. Trigger-Jobs erben mit extends: eine gemeinsame Template-Konfiguration, sodass strategy: depend einmal definiert und nicht für jeden Trigger-Job wiederholt wird. Ein when: manual-Gate für das Produktions-Deployment ist direkt in den Pipeline-Graph integriert.

Platform-Teams nutzen dieses Muster, um Dutzende von Umgebungen zu verwalten, ohne Pipeline-Logik zu duplizieren.

Dynamic pipelineDynamic pipeline

4. MR-First-Delivery: Merge-Request-Pipelines, Merged-Results und Workflow-Routing

Das Problem: Die Pipeline läuft bei jedem Push auf jeden Branch. Aufwändige Tests werden auf Feature-Branches ausgeführt, die nie gemergt werden. Gleichzeitig gibt es keine Garantie, dass das Getestete dem entspricht, was nach dem Merge auf main tatsächlich landet.

GitLab kombiniert drei ineinandergreifende Mechanismen: Merge-Request-Pipelines laufen ausschließlich dann, wenn ein Merge Request existiert – nicht bei jedem Branch-Push. Allein dadurch entfällt ein erheblicher Anteil unnötiger Compute-Ausführungen. Merged-Results-Pipelines gehen einen Schritt weiter: GitLab erstellt einen temporären Merge-Commit aus dem Branch und dem aktuellen Ziel-Branch und führt die Pipeline dagegen aus. Getestet wird damit das tatsächliche Ergebnis des Merges – nicht der Branch in Isolation. Workflow-Rules definieren schließlich, welcher Pipeline-Typ unter welchen Bedingungen ausgeführt wird. Die $CI_OPEN_MERGE_REQUESTS-Guard verhindert dabei, dass für einen Branch mit offenem MR doppelte Pipelines ausgelöst werden.

Das Ergebnis ist ein Pipeline-Verhalten, das sich je nach Kontext unterscheidet: Ein Push auf einen Feature-Branch ohne offenen MR führt nur Lint und Unit-Tests aus. Sobald ein MR geöffnet wird, wechseln die Workflow-Rules auf eine MR-Pipeline mit der vollständigen Test-Suite gegen das Merged-Result. Ein Merge auf main stellt ein manuelles Produktions-Deployment in die Warteschlange. Der Nightly-Scan läuft einmalig als geplante Pipeline – nicht bei jedem Commit.

Merged-Results-Pipelines fangen dabei die Klasse von Fehlern ab, die erst nach einem Merge sichtbar werden – bevor sie main erreichen.

5. Governed Pipelines: CI/CD Components

Das Problem: Das Platform-Team hat den richtigen Weg für Build, Test und Deploy definiert. Jedes Anwendungsteam pflegt jedoch eine eigene .gitlab-ci.yml mit subtilen Abweichungen. Security-Scanning wird übersprungen. Deployment-Standards driften. Audits werden aufwändig.

CI/CD Components ermöglichen es Platform-Teams, versionierte, wiederverwendbare Pipeline-Bausteine zu veröffentlichen. Anwendungsteams binden sie mit einer einzigen include:-Zeile ein – kein Copy-Paste, kein Drift. Components sind über den CI/CD Catalog auffindbar, sodass Teams bewährte Bausteine finden und übernehmen können, ohne das Platform-Team direkt einschalten zu müssen.

Drei Zeilen include: ersetzen hunderte von duplizierten YAML-Zeilen. Das Platform-Team kann einen Security-Fix in einer neuen Komponentenversion veröffentlichen – Teams steigen auf ihrem eigenen Zeitplan um, oder das Platform-Team fixiert alle auf eine Mindestversion. In beiden Fällen propagiert eine Änderung organisationsweit, statt repo-für-repo angewendet zu werden.

Kombiniert mit Resource Groups zur Vermeidung konkurrierender Deployments und Protected Environments für Freigabe-Gates entsteht eine governed Delivery-Plattform, auf der Compliance der Standard ist, nicht die Ausnahme. Platform-Teams setzen Vorgaben durch, ohne zum Engpass zu werden.

Component pipeline (imported jobs)Component pipeline (imported jobs)

Das Modell als Ganzes

Keines dieser Muster existiert isoliert. Der Wert von GitLabs Pipeline-Modell liegt in der Kombinierbarkeit seiner Bausteine:

  • Ein Monorepo nutzt Parent-Child-Pipelines, und jede Child-Pipeline nutzt DAG-Execution.
  • Eine Microservices-Plattform nutzt Multi-Project-Pipelines, und jedes Projekt nutzt MR-Pipelines mit Merged-Results.
  • Eine governed Plattform nutzt CI/CD Components, um die obigen Muster organisationsweit zu standardisieren.

Die meisten Teams entdecken eines dieser Muster, wenn sie auf ein konkretes Problem stoßen. Teams, die das vollständige Modell verstehen, entwickeln daraus eine Delivery-Infrastruktur, die tatsächlich abbildet, wie ihre Engineering-Organisation arbeitet – und mit ihr wächst.

Weitere Muster

Das Pipeline-Modell geht über die fünf vorgestellten Muster hinaus:

GitLab Ultimate kostenlos testen und Pipeline-Logik ab heute einsetzen.

Für deutsche Unternehmen: Regulatorischer Kontext

Teams, die Pipeline-Governance nach Muster 5 einführen, adressieren dabei möglicherweise auch Anforderungen, die regulatorische Frameworks an sichere Softwareentwicklungsprozesse stellen.

CI/CD Components mit erzwungenen Security-Gates könnten Anforderungen an sichere Entwicklungsprozesse betreffen – beispielsweise in Bereichen, die Frameworks wie NIS2, ISO 27001 oder BSI IT-Grundschutz an den Software-Entwicklungslebenszyklus adressieren. Protected Environments und Resource Groups betreffen ähnliche Themen im Bereich Änderungskontrolle und Umgebungstrennung, wie sie in Governance-Frameworks typischerweise explizit formuliert sind.

Multi-Project-Pipelines mit API-Contract-Validierung (Muster 2) schaffen Sichtbarkeit über Service-Abhängigkeiten hinweg – ein Aspekt, den Frameworks zur Lieferkettensicherheit adressieren.

Merged-Results-Pipelines (Muster 4) dokumentieren automatisch, dass das tatsächliche Merge-Ergebnis getestet wurde, nicht nur der Feature-Branch in Isolation. Dies könnte Anforderungen an nachvollziehbare Änderungsprozesse betreffen, wie sie in Change-Management-Kontrollen verschiedener Sicherheitsframeworks formuliert sind.

Für konkrete Compliance-Anforderungen im eigenen regulatorischen Umfeld empfiehlt sich Rücksprache mit entsprechender Fachberatung.

Abschnitt 2: Konfiguration und Implementierung

Für Entwicklungsteams und DevOps-Praktiker: ausgewählte Konfigurationsbeispiele zu den Mustern 1, 4 und 5. Für vollständige Konfigurationen aller Muster: englischer Originalartikel.

Die folgenden Konfigurationen sind illustrativ aufgebaut. Die Skripte verwenden echo-Befehle, um das Wesentliche sichtbar zu halten. Für den produktiven Einsatz werden die echo-Befehle durch die tatsächlichen Build-, Test- und Deploy-Schritte ersetzt.

Muster 1: Parent-Child-Pipelines und DAG-Execution

Eine Parent-Pipeline erkennt Änderungen und löst nur die betroffenen Child-Pipelines aus:

        - trigger

trigger-services:
  stage: trigger
  trigger:
    include:
      - local: '.gitlab/ci/api-service.yml'
      - local: '.gitlab/ci/web-service.yml'
      - local: '.gitlab/ci/worker-service.yml'
    strategy: depend

    

Innerhalb der Child-Pipeline ermöglicht needs: DAG-Execution – der Test startet, sobald der Build abgeschlossen ist, ohne auf andere Jobs in derselben Stage zu warten:

        - build
  - test

build-api:
  stage: build
  script:
    - echo "Building API service"

test-api:
  stage: test
  needs: [build-api]
  script:
    - echo "Running API tests"

    

Local downstream pipelinesLocal downstream pipelines

Muster 4: MR-First-Delivery

Workflow-Rules, MR-Pipelines und Merged-Results zusammen ergeben ein kontextabhängiges Pipeline-Verhalten:

        rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
      when: never
    - if: $CI_COMMIT_BRANCH
    - if: $CI_PIPELINE_SOURCE == "schedule"

stages:
  - fast-checks
  - expensive-tests
  - deploy

lint-code:
  stage: fast-checks
  script:
    - echo "Running linter"
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

unit-tests:
  stage: fast-checks
  script:
    - echo "Running unit tests"
  rules:
    - if: $CI_PIPELINE_SOURCE == "push"
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

integration-tests:
  stage: expensive-tests
  script:
    - echo "Running integration tests (15 min)"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

e2e-tests:
  stage: expensive-tests
  script:
    - echo "Running E2E tests (30 min)"
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"

nightly-comprehensive-scan:
  stage: expensive-tests
  script:
    - echo "Running full nightly suite (2 hours)"
  rules:
    - if: $CI_PIPELINE_SOURCE == "schedule"

deploy-production:
  stage: deploy
  script:
    - echo "Deploying to production"
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
      when: manual

    

Conditional pipelines (within a branch with no MR)Conditional pipelines (within a branch with no MR)

Conditional pipelines (within an MR)Conditional pipelines (within an MR)

Conditional pipelines (on the main branch)Conditional pipelines (on the main branch)

Muster 5: CI/CD Components

Eine Komponentendefinition aus einer gemeinsamen Bibliothek:

        inputs:
    stage:
      default: deploy
    environment:
      default: production
--- deploy-job:
  stage: $[[ inputs.stage ]]
  script:
    - echo "Deploying $APP_NAME to $[[ inputs.environment ]]"
    - echo "Deploy URL: $DEPLOY_URL"
  environment:
    name: $[[ inputs.environment ]]

    

So bindet ein Anwendungsteam die Komponenten ein:

        APP_NAME: "my-awesome-app"
  DEPLOY_URL: "https://api.example.com"

include:
  - component: gitlab.com/my-org/component-library/[email protected]
  - component: gitlab.com/my-org/component-library/[email protected]
  - component: gitlab.com/my-org/component-library/[email protected]
    inputs:
      environment: staging

stages:
  - build
  - test
  - deploy

    

Orientierung zu den Mustern 2 und 3

Muster 2 (Multi-Project-Pipelines): Das Frontend-Repository publiziert ein API-Contract-Artifact und löst anschließend die Backend-Pipeline aus. Das Backend ruft das Artifact über die GitLab Jobs API ab und validiert es. Der integration-test-Job läuft dabei nur dann, wenn er von einer Upstream-Pipeline ausgelöst wurde ($CI_PIPELINE_SOURCE == "pipeline"), nicht bei einem eigenständigen Push. Die Frontend-Projekt-ID wird als CI/CD-Variable gesetzt, um Hardcoding zu vermeiden. Vollständige Konfigurationen beider Repositories: englischer Originalartikel.

Muster 3 (Dynamische Child-Pipelines): Ein generate-config-Job erzeugt zur Laufzeit environment-spezifische YAML-Dateien. Trigger-Jobs nutzen extends: für gemeinsam genutzte Konfiguration und needs: für sequenzielle Promotion (dev → staging → prod mit manuellem Gate). Vollständige Konfiguration: englischer Originalartikel.

Weiterführende Artikel

Feedback erwünscht

Dieser Blogbeitrag hat gefallen oder es gibt Fragen oder Feedback? Ein neues Diskussionsthema im GitLab-Community-Forum erstellen und Eindrücke austauschen.

Feedback teilen

Beginne noch heute, schneller zu entwickeln

Entdecke, was dein Team mit der intelligenten Orchestrierungsplattform für DevSecOps erreichen kann.