GitLab CI/CD ist eine Plattform für Continuous Integration und Delivery, die direkt in GitLab integriert ist. Anders als externe CI-Tools, die separate Konfigurationen und Webhooks benötigen, liest GitLab CI/CD eine einzige .gitlab-ci.yml-Datei aus dem Repository und führt Pipelines automatisch bei jedem Push aus. Diese enge Integration bedeutet, dass Code, Issues, Merge Requests und Deployment-Pipelines an einem einzigen Ort zusammenleben.

Diese Anleitung führt Schritt für Schritt durch die Pipeline-Konfiguration — Stages, Jobs, Runner, Caching, Artefakte, Variablen, Environments und Deployment-Strategien, die in der Produktion funktionieren.

Voraussetzungen

  • Ein GitLab-Account (gitlab.com oder selbst gehostete Instanz)
  • Ein auf GitLab gehostetes Git-Repository
  • Grundkenntnisse der YAML-Syntax
  • Docker installiert (für Runner mit Docker-Executor)
  • Vertrautheit mit CI/CD-Konzepten (Build, Test, Deploy)

Die Struktur einer GitLab CI/CD Pipeline verstehen

Eine Pipeline besteht aus Stages, die sequenziell ablaufen, und Jobs innerhalb jeder Stage, die parallel ausgeführt werden. Hier ist die grundlegende Struktur:

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

build-app:
  stage: build
  image: node:20
  script:
    - npm ci
    - npm run build
  artifacts:
    paths:
      - dist/
    expire_in: 1 hour

unit-tests:
  stage: test
  image: node:20
  script:
    - npm ci
    - npm run test:unit
  coverage: '/Lines\s+:\s+(\d+\.?\d*)%/'

integration-tests:
  stage: test
  image: node:20
  services:
    - postgres:15
  variables:
    POSTGRES_DB: test_db
    POSTGRES_USER: runner
    POSTGRES_PASSWORD: testing
    DATABASE_URL: "postgresql://runner:testing@postgres:5432/test_db"
  script:
    - npm ci
    - npm run test:integration

deploy-staging:
  stage: deploy
  script:
    - ./scripts/deploy.sh staging
  environment:
    name: staging
    url: https://staging.example.com
  rules:
    - if: $CI_COMMIT_BRANCH == "develop"

Die build-Stage läuft zuerst. Wenn sie erfolgreich ist, werden beide Test-Jobs parallel ausgeführt (sie befinden sich in derselben Stage). Erst wenn alle Tests bestanden haben, wird das Deployment fortgesetzt.

GitLab Runner konfigurieren

Runner führen die Pipeline-Jobs aus. Es gibt zwei Möglichkeiten:

Shared Runners (Schnellstart)

GitLab.com stellt Shared Runners kostenlos bereit. Sie sind sofort verfügbar — kein Setup erforderlich. Navigiere zu Settings → CI/CD → Runners, um zu prüfen, ob sie aktiviert sind.

Self-Hosted Runner (Produktion)

Für bessere Performance und Kontrolle kannst du einen eigenen Runner installieren:

# GitLab Runner auf Ubuntu installieren
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
sudo apt-get install gitlab-runner

# Den Runner registrieren
sudo gitlab-runner register \
  --url "https://gitlab.com/" \
  --registration-token "YOUR_TOKEN" \
  --executor "docker" \
  --docker-image "alpine:latest" \
  --description "production-runner" \
  --tag-list "docker,linux" \
  --run-untagged="true"

Vergleich der Runner-Executors

ExecutorIsolationGeschwindigkeitAnwendungsfall
DockerHoch (Container pro Job)SchnellStandardwahl für die meisten Projekte
ShellKeine (läuft auf dem Host)Am schnellstenEinfache Skripte, Legacy-Anwendungen
Docker MachineHoch + AutoscalingVariabelCloud-basierte Autoscaling-Runner
KubernetesHoch (Pod pro Job)MittelKubernetes-native Deployments
VirtualBoxVollständige VMLangsamWenn vollständige OS-Isolation benötigt wird

Erweiterte Pipeline-Konfiguration

Abhängigkeiten cachen

Caching verhindert, dass Abhängigkeiten bei jedem Pipeline-Lauf neu heruntergeladen werden:

variables:
  NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.npm"

cache:
  key:
    files:
      - package-lock.json
  paths:
    - .npm/
    - node_modules/
  policy: pull-push

Die key.files-Direktive generiert einen Cache-Schlüssel aus der package-lock.json. Wenn sich Abhängigkeiten ändern, wird der Cache automatisch invalidiert.

Artefakte zwischen Stages

Build-Ergebnisse von einer Stage an die nächste weitergeben:

build:
  stage: build
  script:
    - npm run build
  artifacts:
    paths:
      - dist/
      - coverage/
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
    expire_in: 1 week

Pipeline-Rules und bedingte Ausführung

Mit rules lässt sich steuern, wann Jobs ausgeführt werden:

deploy-production:
  stage: deploy
  script:
    - ./deploy.sh production
  environment:
    name: production
    url: https://example.com
  rules:
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
      when: manual
    - when: never

Dieser Job erscheint nur bei Versions-Tags (v1.2.3) und erfordert eine manuelle Genehmigung.

Parallele Matrix-Jobs

Gleichzeitig über mehrere Versionen testen:

test:
  stage: test
  image: node:${NODE_VERSION}
  parallel:
    matrix:
      - NODE_VERSION: ["18", "20", "22"]
        DATABASE: ["postgres", "mysql"]
  script:
    - npm ci
    - npm run test

Das erzeugt 6 parallele Jobs (3 Node-Versionen × 2 Datenbanken).

CI/CD-Variablen und Secrets

Sensible Werte sicher speichern:

deploy:
  stage: deploy
  script:
    - echo "$DEPLOY_KEY" > key.pem
    - chmod 600 key.pem
    - scp -i key.pem dist/* user@server:/var/www/
  after_script:
    - rm -f key.pem

Praxisbeispiel: Dein Team deployt eine Node.js-Anwendung in drei Environments — Development, Staging und Production. Jedes Environment hat unterschiedliche Datenbank-Zugangsdaten, API-Schlüssel und Server-Adressen. Diese werden als GitLab CI/CD-Variablen gespeichert, die dem jeweiligen Environment zugeordnet sind. Dieselbe Pipeline-YAML verwaltet alle Deployments; nur die Variablen unterscheiden sich. Wenn ein Entwickler auf develop pusht, deployt die Pipeline automatisch auf Staging. Das Production-Deployment wird nur bei Tags mit manueller Genehmigung durch einen Team-Lead ausgelöst.

Variablentypen und Scoping

ScopeEingestellt inVerfügbar für
ProjectSettings → CI/CD → VariablesAlle Pipelines im Projekt
GroupGroup → Settings → CI/CDAlle Projekte in der Gruppe
InstanceAdmin → CI/CD → VariablesAlle Projekte der Instanz
EnvironmentSettings → CI/CD → Variables (Env-Filter)Jobs, die auf dieses Environment abzielen
Jobvariables: in .gitlab-ci.ymlNur dieser spezifische Job

Markiere Variablen als Protected (nur auf geschützten Branches/Tags verfügbar) und Masked (in Job-Logs verborgen) für Zugangsdaten.

Deployment-Environments und Strategien

Review Apps (Dynamische Environments)

Für jeden Merge Request eine temporäre Umgebung erstellen:

review:
  stage: deploy
  script:
    - deploy_review_app "$CI_MERGE_REQUEST_IID"
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    url: https://$CI_MERGE_REQUEST_IID.review.example.com
    on_stop: stop-review
  rules:
    - if: $CI_MERGE_REQUEST_IID

stop-review:
  stage: deploy
  script:
    - teardown_review_app "$CI_MERGE_REQUEST_IID"
  environment:
    name: review/$CI_MERGE_REQUEST_IID
    action: stop
  rules:
    - if: $CI_MERGE_REQUEST_IID
      when: manual

Production-Deployment mit Rollback

deploy-production:
  stage: deploy
  script:
    - ./deploy.sh production
  environment:
    name: production
    url: https://example.com
    auto_stop_in: never
  rules:
    - if: $CI_COMMIT_TAG
      when: manual
  allow_failure: false

GitLab CI/CD im Vergleich mit anderen CI-Plattformen

FeatureGitLab CI/CDGitHub ActionsJenkinsCircleCI
Konfigurationsdatei.gitlab-ci.yml.github/workflows/*.ymlJenkinsfile.circleci/config.yml
Integrierte RegistryJa (Container + Package)Ja (Container)NeinNein
Self-hosted OptionJa (vollständiges GitLab)Ja (nur Runner)JaNein
Review AppsNativManuelles SetupManuellManuell
DAG PipelinesJa (needs-Schlüsselwort)Ja (nativ)JaJa
Auto DevOpsJaNeinNeinNein
Kostenlose CI-Minuten400 Min./Monat2.000 Min./MonatUnbegrenzt (self-hosted)6.000 Min./Monat
LernkurveMittelNiedrigHochNiedrig

GitLab CI/CD glänzt, wenn alles integriert sein soll — Code, CI, Container-Registry, Environments und Monitoring auf einer Plattform. GitHub Actions punktet mit der Breite seines Marketplace-Ökosystems.

Fallstricke und Sonderfälle

  • YAML-Anchors funktionieren nicht mit include: Wenn YAML-Anchors (&anchor/*anchor) in eingebundenen Dateien verwendet werden, lösen sie sich nicht über Dateigrenzen hinweg auf. Verwende stattdessen das extends-Schlüsselwort.

  • Cache ist nicht garantiert: GitLab-Caches sind eine Best-Effort-Funktion. Runner teilen sich möglicherweise keinen Cache. Entwirf Pipelines immer so, dass sie auch ohne Cache funktionieren (nur langsamer).

  • Services-Netzwerk: Service-Container (wie postgres:15) sind über ihren Image-Namen als Hostname erreichbar — postgres, nicht localhost. Das verwirrt viele Entwickler.

  • only/except vs rules: Die veraltete only/except-Syntax ist nicht mit rules kompatibel. Niemals beides im selben Job mischen. Bevorzuge rules — es ist mächtiger und der empfohlene Ansatz.

  • Job-Timeout standardmäßig 1 Stunde: Lang laufende Jobs wie E2E-Tests oder große Builds schlagen am Timeout stillschweigend fehl. Setze timeout: 2h explizit für bekannte lang laufende Jobs.

  • Variablen für geschützte Branches: Als “Protected” markierte Variablen sind auf Feature-Branches nicht verfügbar. Wenn ein Job Zugangsdaten auf nicht geschützten Branches benötigt, verwende eine separate Variable ohne das Protected-Flag.

Fehlerbehebung

ProblemUrsacheLösung
Pipeline bleibt bei “Pending” hängenKeine verfügbaren Runner mit passenden TagsRunner-Tags prüfen oder tags: [] setzen, um beliebige Runner zu verwenden
”Cache not found” beim ersten LaufCache wurde noch nicht erstelltErster Lauf lädt alles herunter; Cache wird für den nächsten Lauf befüllt
Services nicht erreichbarFalscher Hostname im Connection StringDen Image-Namen des Services als Hostname verwenden (z. B. postgres, nicht localhost)
“Variable is not set” in JobsVariable ist geschützt, Branch ist es nicht”Protected” deaktivieren oder auf einen geschützten Branch pushen
Artefakte in der nächsten Stage fehlenartifacts.paths stimmt nicht mit der Ausgabe übereinGenaue Pfade prüfen; ls -la im Skript zur Fehlersuche verwenden

Zusammenfassung

  • GitLab CI/CD liest .gitlab-ci.yml aus dem Repository und führt Pipelines automatisch aus — keine externe Tool-Konfiguration nötig
  • Stages laufen sequenziell, während Jobs innerhalb einer Stage parallel ausgeführt werden — das gibt sowohl Reihenfolge als auch Geschwindigkeit
  • Self-hosted Runner mit Docker-Executor bieten die beste Performance und Kontrolle für Produktionsteams
  • Caching von Abhängigkeiten und die Weitergabe von Artefakten zwischen Stages reduziert die Pipeline-Laufzeit erheblich
  • Umgebungsvariablen mit Maskierung, Schutz und Environment-Scoping halten Secrets über alle Deployments hinweg sicher
  • Review Apps erstellen temporäre Environments pro Merge Request und ermöglichen so eine visuelle Überprüfung vor dem Merge

Verwandte Artikel