Was ist GitLab CI/CD?
GitLab CI/CD (Continuous Integration / Continuous Deployment) ist ein in GitLab integriertes System zur automatisierten Ausführung von Builds, Tests und Deployments. Anders als bei externen Lösungen wie Jenkins oder CircleCI läuft die gesamte Konfiguration direkt im Repository – zentral verwaltet und versioniert. Das Herzstück ist die Datei .gitlab-ci.yml im Wurzelverzeichnis deines Projekts.
Die Vorteile liegen auf der Hand: Jeder Commit durchläuft automatisch definierte Pipelines, Fehler werden frühzeitig erkannt, und die Auslieferung neuer Versionen lässt sich vollständig automatisieren. GitLab CI/CD unterstützt dabei eine Vielzahl von Sprachen und Frameworks – von einfachen statischen Webseiten bis hin zu komplexen Microservice-Architekturen.
Grundlagen: Architektur von GitLab CI/CD
Bevor wir mit der Konfiguration beginnen, ist es wichtig, die grundlegende Architektur zu verstehen. GitLab CI/CD besteht aus mehreren Komponenten, die zusammenspielen:
| Komponente | Beschreibung |
|---|---|
| GitLab Server | Die zentrale Plattform, die Repositorys verwaltet und Pipelines orchestriert. Verfügbar als GitLab.com (SaaS) oder Self-Hosted (GitLab EE/CE). |
| GitLab Runner | Ein Agent, der Jobs einer Pipeline ausführt. Runner können auf eigenen Maschinen, in Containern oder in der Cloud (z. B. AWS, GCP) betrieben werden. |
| Pipeline | Eine Abfolge von Stages, die nacheinander oder parallel ausgeführt werden. Jede Stage enthält einen oder mehrere Jobs. |
| .gitlab-ci.yml | Die YAML-Konfigurationsdatei, die alle Stages, Jobs, Abhängigkeiten und Umgebungsvariablen definiert. |
| Docker Executor | Der am häufigsten genutzte Executor-Typ für GitLab Runner. Er führt Jobs in isolierten Docker-Containern aus. |
Schritt 1: GitLab Runner installieren und registrieren
Der GitLab Runner ist die ausführende Komponente. Ohne einen registrierten Runner werden deine Pipelines nicht gestartet. So installierst du ihn auf einem Linux-Server:
Installation unter Ubuntu/Debian:
# Offizielles GitLab-Repository hinzufügen
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
# GitLab Runner installieren
sudo apt-get install gitlab-runner
# Runner registrieren
sudo gitlab-runner register \
--url https://gitlab.com \
--registration-token DEIN_TOKEN \
--executor docker \
--docker-image alpine:latest \
--description "Mein Docker-Runner"
Nach der Registrierung erscheint der Runner in den GitLab-Einstellungen deines Projekts unter Settings → CI/CD → Runners. Von dort aus kannst du ihn verwalten und überwachen.
Schritt 2: Die .gitlab-ci.yml Grundstruktur
Die Datei .gitlab-ci.yml definiert deine gesamte Pipeline. Hier eine einfache Beispielkonfiguration für ein Node.js-Projekt:
stages:
- build
- test
- deploy
image: node:20-alpine
variables:
NODE_ENV: production
PROJECT_NAME: "mein-projekt"
before_script:
- node --version
- npm ci --cache .npm
build-app:
stage: build
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
test-app:
stage: test
script:
- npm run lint
- npm run test:unit
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
deploy-staging:
stage: deploy
script:
- echo "Deploying to staging..."
environment:
name: staging
url: https://staging.mein-projekt.de
only:
- main
Dieses Beispiel zeigt die drei klassischen Stages: build (Kompilieren und Erstellen der Artefakte), test (Linting und Unit-Tests) und deploy (Auslieferung auf eine Staging-Umgebung). Jeder Job läuft in einem frischen Docker-Container auf Basis des angegebenen image.
Schritt 3: Stages und Jobs sinnvoll strukturieren
Eine gute Pipeline-Struktur ist entscheidend für effiziente Entwicklungsabläufe. GitLab CI/CD unterscheidet zwischen Stages (Phasen) und Jobs (einzelne Aufgaben). Jobs innerhalb derselben Stage laufen parallel, Stages nacheinander. So kannst du komplexe Abläufe abbilden:
stages:
- build
- test
- security
- package
- staging
- production
code-quality:
stage: test
script:
- npm run lint
- npm run format:check
security-scan:
stage: security
script:
- npm audit --audit-level=high
- trivy image mein-image:latest
package:
stage: package
script:
- docker build -t mein-image:${CI_COMMIT_SHORT_SHA} .
- docker push registry.gitlab.com/mein-projekt/mein-image:${CI_COMMIT_SHORT_SHA}
Moderne CI/CD-Pipelines enthalten oft deutlich mehr als drei Stages. Security-Scans, Compliance-Checks, Performance-Tests und Package-Erstellung sind typische Erweiterungen. Wichtig ist, dass jede Stage einen klaren Zweck erfüllt und die Pipeline feingranular genug ist, um Fehler schnell zu lokalisieren.
Schritt 4: Docker-basierte Builds und Caching
Docker ist der De-facto-Standard für GitLab CI/CD. Mit dem Docker Executor kannst du jeden Job in einem isolierten Container ausführen. Noch wichtiger ist das richtige Caching, um Build-Zeiten drastisch zu reduzieren:
variables:
npm_config_cache: "$CI_PROJECT_DIR/.npm"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/
- node_modules/
build:
stage: build
script:
- npm ci
- npm run build
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/
- node_modules/
- dist/
policy: push
test:
stage: test
script:
- npm ci
- npm run test
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .npm/
- node_modules/
policy: pull
Durch die Trennung von Cache-Policies (push nach dem Build, pull vor dem Test) stellst du sicher, dass Abhängigkeiten nicht mehrfach heruntergeladen werden. Gerade bei großen JavaScript- oder Python-Projekten sparst du so mehrere Minuten pro Pipeline-Lauf.
Schritt 5: Deployment-Automatisierung
Der wohl wichtigste Teil einer CI/CD-Pipeline ist das automatisierte Deployment. GitLab bietet hierfür mehrere Mechanismen. Ein bewährtes Beispiel für ein Deployment per SSH auf einen eigenen Server:
deploy-production:
stage: production
image: alpine:latest
before_script:
- apk add --no-cache openssh-client rsync
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
script:
- rsync -avz --delete dist/ user@server:/var/www/mein-projekt/
- ssh user@server "sudo systemctl reload nginx"
environment:
name: production
url: https://mein-projekt.de
only:
- main
when: manual
Beachte das when: manual – damit wird der Job nicht automatisch ausgeführt, sondern muss manuell über die GitLab-Weboberfläche gestartet werden. Das ist für Production-Deployments dringend zu empfehlen, um versehentliche Auslieferungen zu vermeiden. Alternativ kannst du auch rules verwenden, um feinere Steuerungslogik abzubilden.
GitLab CI/CD vs. GitHub Actions: Ein Vergleich
Viele Entwickler stehen vor der Frage: GitLab CI/CD oder GitHub Actions? Beide Systeme sind leistungsfähig, unterscheiden sich aber in einigen wesentlichen Punkten:
| Kriterium | GitLab CI/CD | GitHub Actions |
|---|---|---|
| Konfiguration | .gitlab-ci.yml im Repository | .github/workflows/*.yml |
| Runner-Management | Eigene Runner einfach installierbar | Self-Hosted Runner über GitHub-Apps |
| Parallelisierung | Native Unterstützung, Stages parallelisierbar | Matrix-Strategie, Job-Needs |
| Integriertes Registry | GitLab Container Registry (Docker, Helm) | GitHub Container Registry (GHCR) |
| Kosten (Free Tier) | 2000 CI/CD Minuten/Monat (GitLab.com) | 2000 Minuten/Monat (GitHub.com) |
| Self-Hosted | GitLab EE/CE auf eigenem Server | GitHub Enterprise Server |
| Pipeline-Syntax | YAML mit extends, includes, templates | YAML mit Composite Actions, Reusable Workflows |
| Dokumentation & Community | Sehr gut, umfangreiche CI/CD-Doku | Exzellent, riesige Marketplace-Community |
Best Practices für GitLab CI/CD Pipelines 2026
Nach zahlreichen Projekten haben sich einige bewährte Praktiken herauskristallisiert, die deine Pipelines robuster, schneller und wartbarer machen:
- DRY-Prinzip mit extends: Nutze
extends, um wiederkehrende Konfigurationen auszulagern. Erstelle Basis-Jobs, von denen spezifische Jobs erben:
.base-job:
image: node:20-alpine
before_script:
- npm ci
build-app:
extends: .base-job
stage: build
script: npm run build
test-app:
extends: .base-job
stage: test
script: npm run test
- Inkludieren von Vorlagen (includes): Lagere wiederkehrende Pipeline-Teile in separate YAML-Dateien aus und binde sie mit
includeein. Das hält die Hauptdatei übersichtlich:
include:
- local: '/ci-templates/build.yml'
- local: '/ci-templates/test.yml'
- local: '/ci-templates/deploy.yml'
- template: 'Security/SAST.gitlab-ci.yml'
- Environment-spezifische Variablen: Nutze GitLab CI/CD-Variablen (unter Settings → CI/CD → Variables), um sensible Daten wie API-Keys oder Passwörter zu speichern. Markiere sie als "masked", damit sie in Logs nicht sichtbar sind.
- Pipeline-Effizienz: Setze
needsein, um Abhängigkeiten zwischen Jobs zu definieren. Das ermöglicht eine feinere Parallelisierung als reine Stages:
test-frontend:
stage: test
needs: ["build-frontend"]
test-backend:
stage: test
needs: ["build-backend"]
deploy:
stage: deploy
needs: ["test-frontend", "test-backend"]
- Automatische Aufräumarbeiten: Konfiguriere
expire_infür Artefakte, um Speicherplatz zu sparen. Setze dazu Werte wie1 dayoder1 week. - Pipeline-Badges: Füge CI/CD-Badges in deine README ein – sie zeigen auf einen Blick den Status der letzten Pipeline und schaffen Vertrauen bei Entwicklern.
Erweiterte Techniken: Multi-Project-Pipelines und Parent-Child
In größeren Projekten mit mehreren Microservices reicht eine einzelne Pipeline oft nicht aus. GitLab CI/CD bietet dafür leistungsfähige Mechanismen:
Multi-Project Pipelines: Du kannst Pipelines in anderen Projekten triggern, wenn dein Projekt von ihnen abhängt. Das ist ideal für Microservice-Architekturen, bei denen Änderungen an einer API automatisch die Tests der abhängigen Dienste anstoßen sollen:
trigger-api-tests:
stage: test
trigger:
project: mein-team/api-tests
branch: main
strategy: depend
Parent-Child Pipelines: Mit dynamisch generierten Child-Pipelines kannst du parallele Ausführungen für verschiedene Komponenten erzeugen. Das ist besonders nützlich für monorepoartige Strukturen, bei denen nur die geänderten Komponenten getestet werden sollen:
generate-child-pipeline:
stage: build
script:
- generate-pipeline-config.sh
artifacts:
paths:
- generated-pipeline.yml
child-pipeline:
stage: test
trigger:
include:
- artifact: generated-pipeline.yml
job: generate-child-pipeline
strategy: depend
Sicherheit in GitLab CI/CD
Sicherheit ist ein zentrales Thema in DevOps-Workflows. GitLab CI/CD bietet mehrere integrierte Funktionen, um deine Pipelines abzusichern:
- CI/CD Variable Protection: Markiere sensitive Variablen als "protected", sodass sie nur in Pipelines für geschützte Branches (z. B.
main) verfügbar sind. - SAST & DAST: Nutze GitLabs integrierte Static Application Security Testing (SAST) und Dynamic Application Security Testing (DAST) Templates, um Schwachstellen automatisch zu erkennen:
include:
- template: Security/SAST.gitlab-ci.yml
- template: Security/Secret-Detection.gitlab-ci.yml
- template: Security/Dependency-Scanning.gitlab-ci.yml
- Secret Detection: GitLab scannt dein Repository automatisch auf versehentlich eingecheckte Secrets wie API-Keys oder Token. Das Feature solltest du unbedingt aktivieren.
- Job Token Scope: Mit CI_JOB_TOKEN können Jobs sicher mit anderen GitLab-APIs oder der Container Registry kommunizieren – ohne manuelle Token-Verwaltung.
Fehlerbehebung: Häufige Probleme und Lösungen
Selbst erfahrene DevOps-Ingenieure stoßen hin und wieder auf Probleme mit GitLab CI/CD. Hier die häufigsten Stolperfallen und ihre Lösungen:
1. "This job is stuck" – kein verfügbarer Runner
Prüfe, ob ein aktiver Runner für dein Projekt registriert ist. Gehe zu Settings → CI/CD → Runners und vergewissere dich, dass mindestens ein Runner den Status "Online" hat. Fehlt der Runner, registriere ihn neu oder nutze die Shared Runner von GitLab.com.
2. Pipeline läuft ewig – Caching-Probleme
Überprüfe deine Cache-Konfiguration. Ein fehlender Cache-Schlüssel führt dazu, dass Abhängigkeiten bei jedem Pipeline-Lauf neu heruntergeladen werden. Setze einen projekt- und branch-spezifischen Cache-Key ein.
3. Berechtigungsfehler beim Deployment
Stelle sicher, dass die verwendeten SSH-Keys oder API-Tokens in den CI/CD-Variablen hinterlegt sind und die nötigen Berechtigungen besitzen. Teste die Verbindung manuell, bevor du sie in der Pipeline verwendest.
4. Docker Build schlägt fehl
Bei selbst gehosteten Runnern mit Docker Executor muss der Runner Benutzer Zugriff auf die Docker-Socket haben (/var/run/docker.sock). In GitLab.com Shared Runnern ist dies standardmäßig aktiviert.
Fazit: GitLab CI/CD lohnt sich
GitLab CI/CD ist eine extrem leistungsfähige Plattform für Continuous Integration und Deployment. Mit der .gitlab-ci.yml hast du die volle Kontrolle über deine Build-, Test- und Deploy-Workflows – alles versioniert und zentral im Repository. Die Integration mit der GitLab Container Registry, der integrierten Security-Scanning-Suite und den flexiblen Trigger-Mechanismen macht GitLab CI/CD zu einer der besten Lösungen am Markt.
Für Einsteiger empfehlen wir, mit einer einfachen Drei-Stufen-Pipeline (Build → Test → Deploy) zu starten und diese nach und nach zu erweitern. Mit der Zeit kommen Security-Scans, Multi-Project-Trigger und optimierte Cache-Strategien hinzu. GitLab CI/CD wächst mit deinen Anforderungen – und dank der umfangreichen Dokumentation und Community findest du für fast jedes Problem eine Lösung.