IT-Admin.tech

Automatisierung: CI/CD-Pipeline mit GitLab CI, Docker-Image-Scanning und automatisierten Rollbacks einrichten

Architekturdiagramm einer CI/CD-Pipeline mit GitLab CI, Trivy Image-Scanning, Container Registry und automatischem...
Schematische Darstellung: GitLab CI, Image-Scanning und Canary-Deploy mit automatischem Rollback in Kubernetes.

Ein zuverlässiger, automatisierter Lieferprozess reduziert Ausfallzeiten und menschliche Fehler im Betrieb von digitalen Unternehmenslösungen. In diesem Beitrag erkläre ich praxisnah, wie Sie eine CI/CD-Pipeline mit GitLab CI aufsetzen, Docker-Image-Scanning integrieren und automatisierte Rollbacks implementieren. Das Ziel ist ein wartbarer Betriebspfad: Build → Test → Scan → Deploy → Beobachtung → automatischer Rollback bei kritischen Fehlern. Das Fokus-Keyword CI/CD-Pipeline mit GitLab CI finden Sie bereits in der Einleitung, damit die Suchintention klar ist.

Warum eine CI/CD-Pipeline mit GitLab CI?

GitLab CI ist ein integriertes CI/CD-System in GitLab, das Pipelines auf Basis von .gitlab-ci.yml ausführt. Für Administratoren ist wichtig: GitLab CI orchestriert Runner (Ausführungsagenten), hat eingebaute Registry-Integrationen und lässt sich mit externen Tools (Scanning, Monitoring) verbinden. Eine strukturierte Pipeline reduziert Deployment-Risiko, automatisiert Sicherheitsprüfungen (Image-Scanning) und ermöglicht rücksichere Deployments (Rollbacks).

Architekturüberblick und Voraussetzungen

Die typische Architektur umfasst GitLab (Repository + CI), GitLab Runners, eine Container-Registry (z. B. GitLab Registry oder ein privates Harbor), ein Image-Scanning-Tool (z. B. Trivy, Clair oder GitLabs Container Scanning), ein Orchestrierungslaufwerk (häufig Kubernetes) und Monitoring/Alerting (z. B. Prometheus + Alertmanager). Voraussetzungen sind:

  • GitLab-Instanz mit Runnern und Registry-Zugriff.
  • Authentifizierte Registry-Zugänge (Tokens/CI_JOB_TOKEN oder Deploy-Keys).
  • Zielumgebung mit Deploy-API (kubectl + Kubeconfig oder Helm).
  • Monitoring mit definierten Health- und SLO-Metriken zur Entscheidungsfindung.
  • Rollback-Mechanismen und Playbooks dokumentiert für Betriebsteams.

Begriffsordination

CI/CD (Continuous Integration / Continuous Deployment) beschreibt automatisierte Schritte von Code-Integration bis zur Auslieferung. Image-Scanning prüft Container-Images auf Schwachstellen und Konfigurationsfehler. Rollback bezeichnet das Zurücksetzen einer Deployment-Änderung, wenn ein Release fehlerhaft ist. SBOM (Software Bill of Materials) ist eine Aufstellung aller Komponenten eines Artifacts und hilft Compliance- und Security-Analysen.

Pipeline-Design: Stages, Verantwortlichkeiten, Policies

Eine praktikable Stage-Struktur:

  1. prepare: Checkout, Artefakt-Vorbereitung
  2. build: Image-Build und Tagging
  3. scan: Image-Scanning (Sicherheits-/Policy-Checks)
  4. test: Unit-, Integration- und Smoke-Tests
  5. deploy: Canary/Primary-Deploy
  6. verify: Healthchecks, Telemetry-Checks
  7. promote / finalize: Promotion nach erfolgreichem Canary

Wichtig ist Trennung von Pflichten: Build- und Scan-Jobs sollten nicht auf demselben Runner wie produktive Deploy-Jobs laufen, um Blast-Radius und Rechte zu minimieren.

Image-Tagging-Strategie

Verwenden Sie unveränderliche Tags (z. B. Git-Commit-SHA oder semver plus build-id). Mutable Tags wie latest sind im produktiven Ablauf problematisch, weil sie Reproduzierbarkeit und Rollback erschweren.

Beispiel .gitlab-ci.yml: minimal, aber betriebssicher

Das folgende Beispiel zeigt Kernstücke: Build, Scan mit Trivy, Push und Deploy in ein Kubernetes-Cluster. Achten Sie auf definierte Secrets und ein sicheres Runner-Setup.

Yaml
stages:
  - build
  - scan
  - test
  - deploy
  - verify

variables:
  IMAGE_REGISTRY: registry.example.local
  IMAGE_NAME: "$IMAGE_REGISTRY/myapp"
  KUBE_CONTEXT: production

build:
  stage: build
  image: docker:24
  services:
    - docker:dind
  script:
    - docker build -t "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA" .
    - docker push "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
  only:
    - main

scan:
  stage: scan
  image: aquasec/trivy:latest
  script:
    - trivy image --severity HIGH,CRITICAL --exit-code 1 --no-progress "$IMAGE_NAME:$CI_COMMIT_SHORT_SHA"
  allow_failure: false

deploy_canary:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl --context="$KUBE_CONTEXT" set image deployment/myapp myapp="$IMAGE_NAME:$CI_COMMIT_SHORT_SHA" --record
    - kubectl --context="$KUBE_CONTEXT" rollout status deployment/myapp --timeout=120s
  when: manual
  only:
    - main

verify_canary:
  stage: verify
  image: curlimages/curl:latest
  script:
    - /usr/local/bin/healthcheck.sh "$KUBE_CONTEXT" "myapp" || exit 1
  allow_failure: false

Warum das funktioniert: Build erzeugt ein unveränderliches Image; Scan bricht die Pipeline bei kritischen Schwachstellen; Deploy verwendet kubectl, um die vorhandene Deployment-Ressource zu aktualisieren; Verify ruft einen Healthcheck auf, der auf Laufzeitmetriken oder Smoke-Tests basiert. Fehler in Scan/Verify verhindern automatische Promotion in die Produktion.

Image-Scanning: Tools, Policies und Fallstricke

Gängige Scanner sind Trivy (schnell, CLI-basiert), Clair (Server), Grype oder GitLabs integrierte Container Scanning (SAST/DAST). Scanner liefern CVE-Listen, Schweregrade und Fix-Versionen. Wählen Sie die Policy-Definition mit Bedacht:

  • Blockierende Schweregrade (z. B. CRITICAL/HIGH) für automatische Abort-Entscheidungen.
  • Allow-listing für akzeptierte, aber bewertete Sicherheitslücken (mit Review-Prozess).
  • Regelmäßiges Datenbank-Update des Scanners (Vulnerability-Feeds) – veraltete DBs erzeugen False-Negatives.

Typische Stolperfallen:

  • Fehlende Authentifizierung gegen Registry: CI_JOB_TOKEN oder deploy-keys fehlen.
  • Image-Caching in Runners maskiert Probleme: Testen Sie Scans gegen gepullte Images, nicht nur lokalen Layern.
  • Scanner-Versionen variieren in CVE-Scans – dokumentieren Sie Versionen für Audit.

Deployment-Strategien und Automatisierte Rollbacks

Automatisierte Rollbacks setzen voraus, dass Deployments reversibel und beobachtbar sind. Häufige Strategien:

  • Blue/Green: Vollständige Parallelumgebung, Traffic-Switch bei Erfolg.
  • Canary: Anteiliger Traffic an neues Release, beobachtete Metriken entscheiden über Promotion.
  • Rolling Update mit Readiness-Probes: Default in Kubernetes, aber begrenzte Sicherheitsgarantie ohne Monitoring.

Rollback-Mechanismen in Kubernetes

In Kubernetes ist der einfachste Rückschritt kubectl rollout undo, das previous ReplicaSet wieder aktiviert. Voraussetzung ist, dass ReplicaSets aufbewahrt werden (default: ja, solange nicht explizit aufgeräumt). Bei Helm-Deployments verwenden Sie helm rollback mit gespeicherten Releases.

Shell
# Rollback auf letzte Revision (kubectl)
kubectl --context=production rollout undo deployment/myapp

# Helm rollback auf Revision 2
helm --kube-context production rollback myapp 2

Wann das scheitert: Rollbacks sind wirkungslos, wenn Datenbankmigrationsschritte inkompatibel rückgängig sind oder wenn Konfigurationsänderungen nicht rückführbar sind. Planen Sie Datenbank-Migrationen als separate, kontrollierte Prozesse (z. B. Migrationen, die forward- und backward-kompatibel sind).

Implementierung eines automatischen Rollback-Triggers

Ein automatisches Rollback sollte nicht blind ausgeführt werden. Gute Trigger sind:

  • Smoke-Tests (Endpoint-Checks, Auth-Flow, DB-Connectivity) schlagen fehl.
  • Fehlerrate steigt über definierte Schwellen (z. B. 5xx > X%).
  • Latenz oder Success-Rate fällt unter definierte SLA-Werte.

Technisch wird der Trigger durch einen Verifikations-Job in der Pipeline oder durch externes Monitoring mit Webhook realisiert. Beispiel für ein Gesundheitsprüfskript, das in verify-Stage genutzt werden kann:

Shell
#!/usr/bin/env bash
# healthcheck.sh: einfache Smoke-Checks für Canary
set -euo pipefail
KUBE_CONTEXT="$1"
DEPLOYMENT="$2"
NAMESPACE="default"
# Beispiel: 3 Versuche, 2 Sekunden Pause
for i in 1 2 3; do
  POD=$(kubectl --context="$KUBE_CONTEXT" -n "$NAMESPACE" get pods -l app="$DEPLOYMENT" -o jsonpath='{.items[0].metadata.name}')
  kubectl --context="$KUBE_CONTEXT" -n "$NAMESPACE" exec "$POD" -- /bin/sh -c 'curl -fsS --max-time 5 http://localhost:8080/healthz' && exit 0 || sleep 2
done
exit 1

Wenn dieses Skript mit Exit-Code 1 endet, sollte ein automatischer Rollbackjob in der Pipeline ausgeführt werden oder ein Alert greifen, der eine automatisierte Runbook-Aktion triggert.

Praktische Pipeline-Erweiterung: Rollback-Job

Ergänzen Sie die .gitlab-ci.yml um einen dedizierten rollback-Job, der nur bei fehlender Verify-Stage ausgelöst wird. Dabei ist wichtig: Rollback-Berechtigungen sollten restriktiv sein (RBAC-Role mit minimalen Rechten), und die Rollback-Aktion sollte idempotent sein.

Yaml
rollback_on_verify_failure:
  stage: deploy
  image: bitnami/kubectl:latest
  when: on_failure
  script:
    - kubectl --context="$KUBE_CONTEXT" rollout undo deployment/myapp || true
  only:
    - main

Hinweis: Verwenden Sie when: on_failure gezielt – in komplexen Pipelines kann das unerwartete Nebeneffekte erzeugen, wenn mehrere Jobs fehlschlagen. Testen Sie das Verhalten in einer Staging-Umgebung.

CI/CD-Pipeline mit GitLab CI: Betrieb, Skalierung und Governance

Skalierung und Governance sind im produktiven Betrieb ebenso wichtig wie die Pipeline-Logik. Wichtige Betriebsthemen:

  • Runner-Skalierung: Setzen Sie GitLab Runner Autoscaling (z. B. Kubernetes-Executor oder Docker Machine) ein, um Lastspitzen ohne manuelle Eingriffe abzudecken.
  • Shared vs. Specific Runners: Shared Runner sind bequem, erhöhen aber das Risiko von Ressourcen-Wettlauf. Verwenden Sie dedizierte Runner für privilegierte Deploy-Jobs.
  • Audit und Compliance: Aktivieren Sie Audit-Logs in GitLab und Bewahren Sie Scan-Reports und SBOMs für Prüfungen auf.

Beispiel: Auszug aus einer GitLab Runner config.toml für einen Kubernetes-Executor mit Autoscaling (vereinfachte Darstellung):

Ini
[[runners]]
  name = "k8s-runner"
  url = "https://gitlab.example.local/"
  token = ""
  executor = "kubernetes"
  [runners.kubernetes]
    namespace = "gitlab-runner"
    image = "alpine:3.18"
    idle_timeout = 1800
    poll_timeout = 180

Warum das hilft: Kubernetes-Executor erzeugt Pods pro Job und begrenzt so Nebeneffekte durch gemeinsam genutzte Runner-Hosts. Achten Sie auf Resource-Requests/Limits, damit Job-Pods keine Node-Ressourcen erschöpfen.

Secrets, RBAC und Least-Privilege

Secrets sollten niemals im Image landen. In GitLab nutzen Sie Protected Variables (maskiert, nur in geschützten Branches verfügbar). Für Deploys ins Kubernetes-Cluster sollten ServiceAccounts mit minimalen RBAC-Rechten verwendet werden — nicht Cluster-Admin-Token.

Yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployer
  namespace: production
rules:
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get","list","watch","update","patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: deployer-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: ci-deployer
  namespace: gitlab-runner
roleRef:
  kind: Role
  name: deployer
  apiGroup: rbac.authorization.k8s.io

Das obige Role/RoleBinding-Beispiel erlaubt dem ServiceAccount nur Deploy- und Rollback-Aktionen im production-Namespace. Diese Granularität reduziert das Risiko durch kompromittierte CI-Tokens.

SBOM, Artefakt-Retention und Registry-Governance

SBOMs machen Abhängigkeiten und enthaltene Bibliotheken nachprüfbar. Trivy kann SBOMs erzeugen; binden Sie diese als Artefakt an Build-Jobs. Halten Sie eine Artefakt- und Image-Retention-Strategie fest: Zu aggressive Garbage-Collection kann Rollbacks verhindern, zu lockere Policies füllen Registry-Speicher.

Shell
# Trivy SBOM erzeugen
trivy image --format cyclonedx --output sbom.cdx.json registry.example.local/myapp:$CI_COMMIT_SHORT_SHA

Empfehlung: Bewahren Sie mindestens die letzten N Images pro Service (z. B. N=10) und SBOMs für gesetzliche Aufbewahrungsfristen, sofern Compliance dies verlangt.

Observability und Alert-to-CI-Integration

Automatisierte Entscheidungen basieren auf Metriken. Definieren Sie klare Alert-Regeln in Prometheus und verknüpfen Sie Alertmanager mit einem Webhook, der einen GitLab-Trigger aufruft oder ein Ticket erstellt. Beispiel einer einfachen Prometheus AlertRule (vereinfachtes Beispiel):

Yaml
groups:
- name: app.rules
  rules:
  - alert: HighErrorRate
    expr: rate(http_requests_total{job="myapp",status=~"5.."}[2m]) > 0.05
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "Hohe Fehlerquote bei myapp"
      runbook: "https://wiki.example.local/runbooks/myapp-rollback"

Alertmanager kann bei Auslösung einen Webhook an ein CI-Trigger-Endpoint senden. Stellen Sie sicher, dass Trigger-Endpoints abgesichert sind und nur autorisierte Alerts Aktionen auslösen.

Garbage Collection, Caching und Performance-Hinweise

Scanner-Performance hängt stark von Netzwerkverfügbarkeit und lokaler Cache-Strategie ab. Vermeiden Sie, dass Runner stetig große Images herunterladen, indem Sie ein lokales Registry-Cache oder Proxy verwenden. Ebenso sollten Sie Docker-in-Docker nur dann verwenden, wenn Runner-Isolation anderweitig nicht möglich ist; Kaniko, BuildKit oder Podman sind oft sicherere Alternativen für Kubernetes-Executor.

Test- und Validierungsstrategie vor produktivem Rollout

Testen Sie jeden Schritt:

  • Runner- und Registry-Zugriff mit Dummy-Images validieren.
  • Scanner-DB-Updates und Exit-Codes prüfen (Trivy –version, trivy db update).
  • Deploy-Rollback in Staging wiederholt durchführen; prüfen Sie ReplicaSet-/Helm-Release-Histories.
  • Simulieren Sie Health-Check-Failures, um automatisierte Rollbacks zu prüfen.
Shell
# Trivy DB-Update (wichtig vor Scans)
trivy db update

Typische Fehlerfälle und Troubleshooting

Fehler: Scan-Jobs dauern sehr lange oder Timeout. Ursachen: Scanner-DB veraltet, Netzwerk-Proxy blockiert Zugriff auf Vulnerability-Feeds, großer Image-Layer-Cache. Prüfschritte: Scanner-Version prüfen, Netzwerkzugriff testen, Image auf lokale Scanner-Ausführung prüfen.

Fehler: Rollback schlägt fehl, da ReplicaSets gelöscht wurden. Ursache: Garbage-Collection/Cluster-Cleanup. Maßnahmen: Stellen Sie Cluster-Policies so ein, dass vorherige ReplicaSets/Releases für definierte Zeit aufbewahrt werden.

Fehler: Datenbank-Inkompatibilität bei Rollback. Ursache: Migrationen, die nicht rückgängig gemacht werden können. Lösung: Migrations in zwei Schritten (vorwärts kompatibel), Feature-Flags verwenden, separate Datenbank-Rollback-Strategien planen.

Runbook: Schnelle Schritt-für-Schritt-Aktionen bei Incident

  1. Alarm prüfen: Metriken, Logs, Deploy-History.
  2. Isolieren: Canary-Traffic sofort zurückschalten oder Service auf vorherige Replikas umstellen.
  3. Rollback ausführen (kubectl rollout undo oder helm rollback).
  4. Post-Mortem: Ursache analysieren, Scanner-Resultate, Testabdeckung, Metrics.
  5. Lessons Learned: Pipeline/Tests/Probes anpassen, Patch bereitstellen.

Fazit: Operative Reife statt nur Automatisierung

Automatisierte CI/CD-Pipelines mit GitLab CI, integriertem Docker-Image-Scanning und klar definierten Rollback-Prozessen reduzieren Risiken erheblich, erfordern aber Disziplin: unveränderliche Image-Tags, saubere Scanner-Policies, observability-basierte Entscheidungen und Rollback-fähige Datenbank-Strategien. Testen Sie Rollbacks regelmäßig in Staging, dokumentieren Sie Runbooks und halten Sie Zugriffsrechte restriktiv. Nur so wird Automation im Betrieb tatsächlich resilient und nicht zur neuen Fehlerquelle.

Weiteres Vorgehen: Starten Sie mit einem kleinen Proof-of-Concept: Build → Trivy-Scan → Canary-Deploy → Verify → Rollback, und erweitern Sie die Pipeline schrittweise mit Monitoring- und Compliance-Checks. Planen Sie regelmäßige Übungen (Chaos-Tests, Rollback-Drills) und Audits von Runner-/Registry-Policies.

Für dieses Thema sind auch Docker Image Scanning und Canary Deployment wichtig. Der Beitrag ordnet diese Aspekte verständlich ein und zeigt, worauf es im Alltag ankommt.

Weiterfuehrend

Passende weitere Inhalte