GitLab CI include: Wiederverwendbare Pipeline-Bausteine ueber mehrere Repositories hinweg
AI generated
CI/CD
.yml
GitLab · CI/CD · Pipeline-Architektur
GitLab CI include: Wiederverwendbare Pipeline-Bausteine
local, project, remote und template im Vergleich

Wer in mehr als einem Repository eine .gitlab-ci.yml pflegt, kennt das Problem: Build-, Test- und Deploy-Jobs werden immer wieder kopiert und driften mit der Zeit auseinander. Das include-Keyword loest genau dieses Problem, indem es Pipeline-Definitionen aus anderen Dateien, anderen Projekten oder sogar externen URLs zur Laufzeit zusammenfuehrt. Dieser Artikel zeigt alle vier include-Varianten im Detail und wie daraus eine zentrale CI-Template-Bibliothek fuer die gesamte Organisation wird.

16 Min. Lesezeit include: CI-Templates DRY-Prinzip Pipeline-Architektur

1. Warum include mehr ist als Kopieren und Einfuegen

In den meisten Teams beginnt die GitLab-CI-Pipeline als eine einzelne .gitlab-ci.yml Datei, die mit dem Projekt waechst. Sobald ein zweites oder drittes Repository dazukommt, entsteht schnell die Versuchung, die funktionierende Pipeline einfach zu kopieren und die Projektnamen anzupassen. Das funktioniert kurzfristig, fuehrt aber mittelfristig zu einem Wartungsalbtraum: Eine Aenderung an der Docker-Registry-URL, ein neuer Cache-Key oder ein zusaetzlicher Security-Scan muss dann in zehn, zwanzig oder hundert Repositories einzeln nachgezogen werden.

include loest dieses Problem, indem es GitLab CI erlaubt, Job-Definitionen aus mehreren Quellen zu einer einzigen effektiven Pipeline zusammenzufuehren, bevor sie ausgefuehrt wird. Die lokale .gitlab-ci.yml wird damit zu einem duennen Einstiegspunkt, der auf gemeinsam gepflegte Bausteine verweist, statt jede Zeile selbst zu enthalten. Vier Varianten stehen zur Verfuegung: local fuer Dateien im selben Repository, project fuer andere Repositories in derselben GitLab-Instanz, remote fuer beliebige HTTPS-URLs und template fuer die von GitLab mitgelieferten Standardvorlagen.

2. include:local: Eine grosse Pipeline in mehrere Dateien aufteilen

Die einfachste Form ist include:local. Sie referenziert eine Datei im selben Repository und im selben Git-Ref wie die aufrufende .gitlab-ci.yml. Das ist besonders dann sinnvoll, wenn eine einzelne Pipeline-Datei unuebersichtlich gross geworden ist, etwa weil sie Build-, Test-, Security- und Deploy-Stages fuer mehrere Microservices in einem Monorepo enthaelt. Statt einer 800 Zeilen langen Datei entstehen dann mehrere fachlich getrennte Dateien unter einem Verzeichnis wie .gitlab/ci/, die sich einzeln uebersichtlich reviewen lassen.

Wichtig ist, dass include:local rein strukturell wirkt und keine Versionierung ueber Repository-Grenzen hinweg bietet, weil Datei und Aufrufer immer aus demselben Commit stammen. Das macht es ideal fuer die Aufteilung innerhalb eines Projekts, aber ungeeignet, wenn mehrere unabhaengige Repositories dieselbe Logik teilen sollen. Fuer den Team-internen Gebrauch reicht es aber vollkommen aus, um Lesbarkeit und Review-Faehigkeit deutlich zu verbessern, ohne die Kontrolle ueber die Pipeline aus der Hand zu geben.


# .gitlab-ci.yml
include:
  - local: '.gitlab/ci/build.yml'
  - local: '.gitlab/ci/test.yml'
  - local: '.gitlab/ci/deploy.yml'

stages:
  - build
  - test
  - deploy

3. include:project: Pipeline-Bausteine aus einem anderen Repository beziehen

include:project geht einen entscheidenden Schritt weiter und erlaubt es, eine Datei aus einem komplett anderen GitLab-Projekt einzubinden, solange der ausfuehrende Nutzer oder Runner Leseberechtigung auf das Quellprojekt hat. Genau das ist die Grundlage fuer eine zentrale CI-Bibliothek: Ein dediziertes Repository, zum Beispiel devops/ci-templates, enthaelt fertige Jobs fuer PHP-Builds, Composer-Caching, PHPUnit-Ausfuehrung oder Deployment auf einen bestimmten Servertyp, und jedes Anwendungsprojekt bindet daraus genau das ein, was es braucht.

Der grosse Vorteil gegenueber Kopieren ist die zentrale Pflege: Wird ein Job in der Bibliothek korrigiert oder erweitert, zum Beispiel um einen neuen PHP-8.4-Compatibility-Check, profitieren alle einbindenden Projekte automatisch davon, sobald sie den referenzierten ref aktualisieren oder wenn kein fester ref gesetzt ist, sogar sofort beim naechsten Pipeline-Lauf. Das birgt allerdings auch ein Risiko: Ohne bewusste Versionierung kann eine Aenderung an der Bibliothek unbeabsichtigt alle abhaengigen Pipelines gleichzeitig brechen, weshalb Versionierung ein eigenes Thema weiter unten in diesem Artikel verdient.


# .gitlab-ci.yml eines Anwendungsprojekts
include:
  - project: 'devops/ci-templates'
    ref: 'v2.4.0'
    file:
      - '/php/build.yml'
      - '/php/phpunit.yml'
      - '/deploy/ssh-deploy.yml'

4. include:remote: Externe URLs und ihre Grenzen

include:remote laedt eine YAML-Datei ueber eine beliebige, oeffentlich erreichbare HTTPS-URL. Das ist praktisch, um Vorlagen von Drittanbietern einzubinden oder Pipeline-Bausteine ueber ein internes, nicht in GitLab liegendes Content-Delivery-System bereitzustellen. In der Praxis ist es aber die am seltensten passende Wahl fuer eine interne Template-Bibliothek, weil GitLab-eigene Authentifizierung dabei nicht greift: Die URL muss ohne GitLab-Token erreichbar sein, was interne, zugriffsbeschraenkte Templates ueber diesen Weg praktisch ausschliesst.

Ein weiterer Unterschied zu include:project ist das Fehlen einer sauberen Versionsanbindung an Git-Refs. Zwar laesst sich eine URL mit einem Tag oder Commit-Hash parametrisieren, etwa raw.githubusercontent.com/org/repo/v1.2.0/template.yml, aber GitLab selbst prueft nicht, ob die referenzierte Datei zu einem bestimmten, ueberpruefbaren Zustand gehoert. Fuer oeffentliche, gut versionierte Vorlagen wie Community-Security-Scanner ist das akzeptabel, fuer unternehmensinterne CI-Bausteine mit Zugriffsbeschraenkung ist include:project die deutlich robustere und sicherere Wahl.


# .gitlab-ci.yml
include:
  - remote: 'https://raw.githubusercontent.com/example-org/ci-lib/v1.3.0/php-lint.yml'

5. include:template: GitLab-eigene Standardvorlagen nutzen

include:template bindet eine der vorgefertigten Vorlagen ein, die GitLab selbst als Teil der Plattform mitliefert, etwa fuer Security-Scans, Auto-DevOps-Stages oder Sprach-spezifische Build-Patterns. Diese Vorlagen liegen im internen GitLab-Verzeichnis gitlab-org/gitlab und werden mit jeder GitLab-Version aktualisiert, ohne dass Nutzer sie selbst pflegen muessen. Sie sind der schnellste Weg, um etablierte Security- oder Compliance-Funktionen ohne eigenen Implementierungsaufwand in eine Pipeline zu bringen.

Der Nachteil ist geringere Kontrolle: Aktualisiert GitLab eine Template-Vorlage, kann sich das Verhalten der eigenen Pipeline ohne eigenes Zutun aendern, sobald kein fester GitLab-Versionsbezug vorliegt. In der Praxis kombinieren viele Teams deshalb include:template fuer GitLab-eigene Standardfunktionen wie SAST oder Dependency Scanning mit include:project fuer alles, was das Team selbst entwickelt und versioniert. Diese Kombination nutzt die Staerken beider Ansaetze, ohne auf die jeweils andere Flexibilitaet verzichten zu muessen.


# .gitlab-ci.yml
include:
  - template: 'Security/SAST.gitlab-ci.yml'
  - project: 'devops/ci-templates'
    file: '/php/build.yml'

6. Aufbau einer zentralen CI-Template-Bibliothek

Eine ausgereifte Template-Bibliothek ist selbst ein Software-Projekt und verdient dieselbe Sorgfalt wie Anwendungscode. Sinnvoll ist eine klare Verzeichnisstruktur pro Sprache oder Technologie, zum Beispiel /php, /node, /docker und /deploy, sowie eine README mit Beispielen, wie jeder Baustein eingebunden wird. Jeder Job in der Bibliothek sollte moeglichst generisch formuliert sein und ueber Variablen wie APP_NAME oder DEPLOY_TARGET parametrisierbar sein, statt projektspezifische Annahmen fest zu verdrahten.

Fuer den Rollout empfiehlt sich ein schrittweises Vorgehen: Zunaechst ein Pilotprojekt vollstaendig auf die Bibliothek umstellen, dann ein zweites, drittes Projekt folgen lassen und erst danach die Migration aller verbleibenden Repositories angehen. So lassen sich Kinderkrankheiten der Templates fruehzeitig erkennen, bevor hundert Projekte gleichzeitig betroffen waeren. Ein eigenes Merge-Request-Template im Bibliotheks-Repository, das an Aenderungen erinnert, alle abhaengigen Projekte zu informieren, verhindert zusaetzlich boese Ueberraschungen bei breaking changes.

7. Versionierung: Warum ref niemals main sein sollte

Der haeufigste Fehler beim Einsatz von include:project ist, den ref-Parameter wegzulassen oder fest auf main zu setzen. Damit zieht jede Pipeline bei jedem Lauf automatisch den aktuellsten Stand der Bibliothek, was bei einer fehlerhaften Aenderung sofort alle abhaengigen Projekte gleichzeitig lahmlegen kann. Stattdessen sollte jedes Anwendungsprojekt einen festen Tag referenzieren, etwa v2.4.0, und diesen bewusst und getestet aktualisieren, wenn eine neue Version der Bibliothek verfuegbar ist.

Semantische Versionierung eignet sich hier hervorragend: Patch-Releases fuer Bugfixes ohne Verhaltensaenderung, Minor-Releases fuer neue, opt-in nutzbare Jobs und Major-Releases fuer Breaking Changes wie umbenannte Variablen oder veraenderte Job-Namen. Ein CHANGELOG.md im Bibliotheks-Repository, das jede Version dokumentiert, macht die Migration fuer abhaengige Teams nachvollziehbar. So bleibt die zentrale Bibliothek ein Produktivitaetsgewinn statt einer Quelle fuer unvorhersehbare Pipeline-Ausfaelle.

8. Parametrisierung mit spec:inputs und Kombination mit rules

Seit GitLab 15.11 koennen Templates ueber einen spec:inputs Block am Dateianfang typisierte Eingabeparameter definieren, die beim include mit übergeben werden. Das ersetzt die frueher gaengige, fehleranfaellige Praxis, Variablen einfach an anderer Stelle in der Pipeline zu setzen und zu hoffen, dass der eingebundene Job sie zufaellig verwendet. Mit inputs wird stattdessen explizit sichtbar, welche Werte ein Template erwartet, inklusive Default-Werten und erlaubter Optionen.

Kombiniert mit rules innerhalb der eingebundenen Jobs lassen sich Bausteine bauen, die sich je nach aufrufendem Kontext unterschiedlich verhalten, etwa ein Deploy-Job, der nur auf dem main-Branch tatsaechlich deployt und auf Feature-Branches lediglich einen Dry-Run durchfuehrt. Diese Kombination aus parametrisierten Templates und kontextabhaengigen Regeln ist der Kern dessen, was eine CI-Bibliothek von einer blossen Sammlung kopierter YAML-Fragmente unterscheidet: Sie verhaelt sich wie eine echte, konfigurierbare Softwarekomponente.


# devops/ci-templates: /deploy/ssh-deploy.yml
spec:
  inputs:
    environment:
      default: 'staging'
      options: ['staging', 'production']
---
deploy:
  stage: deploy
  script:
    - echo "Deploying to $[[ inputs.environment ]]"
  rules:
    - if: '$CI_COMMIT_BRANCH == "main" && $[[ inputs.environment ]] == "production"'
    - if: '$CI_COMMIT_BRANCH != "main"'
      when: manual

9. Best Practices, Fallstricke und Vergleich der vier Varianten

In der Praxis bewaehrt sich eine klare Faustregel: include:template fuer alles, was GitLab selbst als Standardfunktion anbietet, include:project fuer selbst entwickelte, versionierte Team-Bausteine, include:local fuer die reine Aufteilung grosser Dateien innerhalb eines Repositories und include:remote nur fuer oeffentliche, extern gepflegte Vorlagen ohne Zugriffsbeschraenkung. Wer alle vier Varianten wahllos mischt, verliert schnell den Ueberblick, welche Aenderung an welcher Stelle vorgenommen werden muss.

Ein haeufiger Fallstrick ist zirkulaeres Includieren, wenn zwei Bibliotheks-Dateien sich gegenseitig referenzieren, was GitLab mit einer klaren Fehlermeldung ablehnt. Ebenso wichtig ist die maximale Tiefe von 150 eingebundenen Dateien pro Pipeline, die in sehr grossen Monorepo-Setups relevant werden kann. Die folgende Tabelle fasst die vier Varianten mit ihren wichtigsten Eigenschaften zusammen, um bei der Wahl der richtigen Methode fuer den jeweiligen Anwendungsfall zu unterstuetzen.

Variante Quelle Versionierung Typischer Einsatz
include:local Gleiches Repository, gleicher Ref Automatisch ueber Commit Grosse Pipelines in Dateien aufteilen
include:project Anderes GitLab-Projekt Via ref (Tag/Branch/SHA) Zentrale, team-eigene CI-Bibliothek
include:remote Beliebige HTTPS-URL Nur manuell ueber URL-Pfad Oeffentliche, extern gepflegte Vorlagen
include:template GitLab-Standardvorlagen An GitLab-Version gekoppelt Security-Scans, Auto-DevOps-Bausteine

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

GitLab CI include: Das Wichtigste auf einen Blick

Vier Varianten

local, project, remote und template decken jeden Anwendungsfall von Datei-Aufteilung bis externer Vorlage ab.

Zentrale Bibliothek

include:project mit festem ref macht ein dediziertes Repository zur Single Source of Truth fuer CI-Jobs.

Versionierung zaehlt

Ein fester Tag statt main verhindert, dass eine Bibliotheks-Aenderung alle Projekte gleichzeitig bricht.

Parametrisierung

spec:inputs macht Templates zu konfigurierbaren Bausteinen statt starren Kopiervorlagen.

11. FAQ: GitLab CI include: Das Wichtigste auf einen Blick

1Was ist der Unterschied zwischen include:local und include:project?
include:local bindet eine Datei aus demselben Repository und demselben Commit ein, waehrend include:project eine Datei aus einem komplett anderen GitLab-Projekt referenziert, versehen mit einem eigenen ref fuer die Versionierung.
2Kann ich mehrere include-Varianten gleichzeitig in einer Pipeline verwenden?
Ja, include akzeptiert eine Liste, in der local, project, remote und template beliebig gemischt werden koennen. GitLab fuehrt alle referenzierten Dateien zu einer einzigen effektiven Pipeline zusammen, bevor sie ausgefuehrt wird.
3Warum sollte ich bei include:project einen festen Tag statt main referenzieren?
Ohne festen ref zieht jede Pipeline automatisch den aktuellsten Bibliotheksstand. Ein fehlerhafter Commit in der Bibliothek wuerde dann sofort alle abhaengigen Projekte gleichzeitig betreffen. Ein fester Tag entkoppelt Aenderungen an der Bibliothek von deren Uebernahme in einzelnen Projekten.
4Funktioniert include:remote auch mit privaten, zugriffsbeschraenkten URLs?
Nein, include:remote unterstuetzt keine GitLab-eigene Authentifizierung. Die referenzierte URL muss ohne Token oeffentlich erreichbar sein, weshalb sich diese Variante nicht fuer interne, zugriffsbeschraenkte Templates eignet.
5Was passiert bei zirkulaeren include-Referenzen?
GitLab erkennt zirkulaere Referenzen, etwa wenn Datei A Datei B einbindet und Datei B wiederum Datei A, und lehnt die Pipeline mit einer eindeutigen Fehlermeldung ab, bevor irgendein Job ausgefuehrt wird.
6Wie viele Dateien kann ich maximal einbinden?
GitLab erlaubt bis zu 150 eingebundene Dateien pro Pipeline und eine maximale Verschachtelungstiefe von includes innerhalb von includes. Fuer die allermeisten Setups ist dieses Limit in der Praxis kein relevanter Faktor.
7Was ist spec:inputs und wozu dient es?
spec:inputs ist ein Block am Anfang einer eingebundenen Datei, der typisierte Eingabeparameter mit Default-Werten und erlaubten Optionen definiert. Er macht explizit sichtbar, welche Werte ein Template erwartet, statt sich auf implizit gesetzte Variablen zu verlassen.
8Sollte jede Organisation eine eigene CI-Template-Bibliothek pflegen?
Ab etwa drei bis fuenf Repositories mit aehnlicher Pipeline-Struktur lohnt sich der Aufwand meist bereits. Bei nur einem oder zwei Projekten ueberwiegt oft noch der Pflegeaufwand fuer ein separates Bibliotheks-Repository den Nutzen.
9Kann ich GitLab-eigene Templates mit eigenen Bausteinen kombinieren?
Ja, das ist sogar eine gaengige Praxis. include:template wird typischerweise fuer Standardfunktionen wie Security-Scans genutzt, waehrend include:project fuer selbst entwickelte, team-spezifische Jobs zum Einsatz kommt, beides in derselben Pipeline.
10Wie migriere ich bestehende Projekte schrittweise auf eine zentrale Bibliothek?
Am sichersten ist ein Pilotprojekt, das vollstaendig umgestellt und ueber mehrere Sprints beobachtet wird, gefolgt von einer schrittweisen Migration weiterer Projekte. Ein CHANGELOG im Bibliotheks-Repository und feste Versions-Tags erleichtern jedem Team den kontrollierten Umstieg.