CI/CD
.yml
GitLab · CI/CD · Magento · Rollback
Rollback-Skript vorbereiten
für Magento-Releases in GitLab

Ein Rollback, der erst im Störfall geschrieben wird, ist keiner. Wer das Rollback-Skript nicht vor dem ersten Deployment fertig hat, testet es zum ersten Mal unter Zeitdruck und Stress — genau dann, wenn alles schnell gehen muss.

12 Min. Lesezeit Rollback-Skript · Symlink · Cache-Flush · Maintenance-Mode · GitLab-Job GitLab CI/CD · Magento 2

1. Die Rollback-Philosophie: Vorbereitung statt Improvisation

Ein Rollback ist kein Sonderfall, sondern ein regulärer Teil des Deployment-Prozesses. Wer Deployments ohne vorbereiteten Rollback-Pfad durchführt, hat keinen Deployment-Prozess — er hat eine Hoffnung. Das klingt hart, ist aber die Erfahrung aus vielen Magento-Projekten: Der Rollback wird vertagt, bis er gebraucht wird, und dann scheitert er an fehlenden Voraussetzungen, Zeitdruck und fehlender Übung.

Das Rollback-Skript muss deshalb als erster Teil des Deployment-Systems entwickelt werden, nicht als letzter. Es muss im Repository versioniert sein, es muss in der GitLab-Pipeline als manueller Job verfügbar sein, und es muss regelmäßig auf Staging getestet werden — mindestens einmal pro Quartal, besser monatlich. Nur ein geübter Rollback ist ein echter Rollback.

Die gute Nachricht für Magento mit symlink-basierter Release-Struktur: Ein Datei-Rollback ist trivial. Das Umschalten des current-Symlinks auf das vorherige Release-Verzeichnis dauert weniger als eine Sekunde. Der schwierige Teil ist nicht die Technik, sondern die Entscheidung — und die Nebeneffekte wie Cache-Zustand, Queue-Nachrichten und Static Content.

2. Voraussetzungen: Was für Rollback vorhanden sein muss

Damit ein Rollback funktioniert, müssen drei Dinge vorhanden sein: Erstens das vorherige Release-Verzeichnis auf dem Server. Wenn alte Releases zu aggressiv gelöscht werden, existiert nichts zum Zurückwechseln. Mindestens das letzte Release muss immer behalten werden — besser drei bis fünf. Zweitens muss der Symlink-Mechanismus korrekt eingerichtet sein. Ein Rollback ist nur möglich, wenn das Deployment nie Dateien direkt überschrieben hat, sondern immer in ein neues Verzeichnis deployt und dann den Symlink umgeschaltet hat. Drittens muss das Rollback-Skript die Zugangsdaten zum Server haben — dieselben SSH-Credentials, die das Deploy-Skript nutzt.

# Verify rollback prerequisites before any production deploy
rollback:check-prerequisites:
  stage: verify
  script:
    - |
      ssh "${DEPLOY_USER}@${DEPLOY_HOST}" bash -s <<'SSH'
      set -euo pipefail
      APP_PATH="${DEPLOY_PATH}"

      # Count available releases for rollback
      release_count=$(ls -1d "${APP_PATH}/releases/"*/ 2>/dev/null | wc -l)
      echo "[INFO] Available releases for rollback: ${release_count}"

      if [[ ${release_count} -lt 2 ]]; then
        echo "[WARN] Only ${release_count} release(s) available — rollback not possible after this deploy"
      fi

      # Verify current symlink exists and resolves correctly
      current_target=$(readlink -f "${APP_PATH}/current" 2>/dev/null || echo "MISSING")
      echo "[INFO] Current release: ${current_target}"

      test -d "${current_target}" \
        || { echo "[FAIL] current symlink target does not exist"; exit 1; }

      echo "[OK] Rollback prerequisites verified"
      SSH
  rules:
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/

3. Das vollständige Rollback-Skript

Das Rollback-Skript hat eine klare Struktur: Zuerst wird das Ziel-Release bestimmt — entweder durch einen explizit übergebenen Parameter oder automatisch als vorletztes Release im releases/-Verzeichnis. Dann werden alle notwendigen Magento-Schritte ausgeführt: Maintenance-Mode einschalten, Symlink umschalten, Cache flushen, Static Content auf das neue Release abgleichen und Maintenance-Mode ausschalten. Jeder Schritt wird protokolliert, Fehler führen zum sofortigen Abbruch.

#!/usr/bin/env bash
# scripts/rollback.sh — Rollback to a previous Magento release
# Usage: ./rollback.sh [release-identifier]
# If no release identifier given, rolls back to the previous release
set -euo pipefail

readonly APP_PATH="${DEPLOY_PATH:?DEPLOY_PATH is not set}"
readonly DEPLOY_HOST_VAR="${DEPLOY_HOST:?DEPLOY_HOST is not set}"
readonly DEPLOY_USER_VAR="${DEPLOY_USER:?DEPLOY_USER is not set}"

# Determine target release — use argument or auto-detect previous
TARGET_RELEASE="${1:-}"

ssh "${DEPLOY_USER_VAR}@${DEPLOY_HOST_VAR}" bash -s <<SSH
set -euo pipefail
APP_PATH="${APP_PATH}"

# Auto-detect previous release if none specified
if [[ -z "${TARGET_RELEASE}" ]]; then
  current_release="\$(readlink -f \${APP_PATH}/current)"
  current_name="\$(basename \${current_release})"
  # List releases sorted by name descending, skip current, take first
  TARGET_RELEASE="\$(ls -1d \${APP_PATH}/releases/*/ \
    | sort -r \
    | grep -v "\${current_name}" \
    | head -1 \
    | xargs basename)"
  echo "[INFO] Auto-detected rollback target: \${TARGET_RELEASE}"
fi

ROLLBACK_PATH="\${APP_PATH}/releases/\${TARGET_RELEASE}"

# Abort if target does not exist
test -d "\${ROLLBACK_PATH}" \
  || { echo "[FAIL] Release \${TARGET_RELEASE} not found on server"; exit 1; }

echo "[ROLLBACK] Switching from \$(basename \$(readlink \${APP_PATH}/current)) to \${TARGET_RELEASE}"

# Enable maintenance mode to prevent user requests during switch
cd "\${APP_PATH}/current"
bin/magento maintenance:enable || echo "[WARN] Could not enable maintenance mode"

# Atomic symlink switch to previous release
ln -sfn "\${ROLLBACK_PATH}" "\${APP_PATH}/current"
echo "[OK] Switched current to \${TARGET_RELEASE}"

# Flush all caches — the previous release may have different cache keys
cd "\${APP_PATH}/current"
bin/magento cache:flush
echo "[OK] Cache flushed"

# Disable maintenance mode
bin/magento maintenance:disable || echo "[WARN] Could not disable maintenance mode"
echo "[ROLLBACK COMPLETE] Now running \${TARGET_RELEASE}"
SSH

4. Rollback-Job in der GitLab-Pipeline

Der Rollback-Job ist ein manueller Job in der rollback-Stage der Pipeline. Er wird nicht automatisch ausgeführt — das würde dazu führen, dass jede Pipeline einen Rollback auslöst. Stattdessen ist er per Klick in der GitLab-Oberfläche auslösbar, ohne dass eine neue Pipeline gestartet werden muss. Die letzte Pipeline, die einen erfolgreichen Deploy durchgeführt hat, enthält auch den Rollback-Job, der auf denselben Server zurückrollt.

Die Variante mit when: manual und ohne allow_failure: false stellt sicher, dass die Pipeline nicht als fehlgeschlagen markiert wird, wenn der Rollback-Job nicht ausgeführt wird. Der Job ist optional — er wird nur im Störfall ausgeführt. Zusätzlich kann eine ROLLBACK_TARGET-Variable als Pipeline-Variable übergeben werden, um einen spezifischen Release als Rollback-Ziel anzugeben.

rollback:production:
  stage: rollback
  environment:
    name: production
    url: https://shop.example.com
  variables:
    # Optional: override with specific release name via GitLab UI pipeline variable
    ROLLBACK_TARGET: ""
  script:
    - chmod +x scripts/rollback.sh
    - ./scripts/rollback.sh "${ROLLBACK_TARGET}"
  rules:
    # Available only on semver tags — same pipeline that deployed the release
    - if: $CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/
      when: manual
      allow_failure: true
  # Rollback job should run even if deploy verify failed
  needs:
    - job: deploy:production
      optional: true

5. Vorgänger-Release automatisch bestimmen

Die automatische Bestimmung des Vorgänger-Release ist ein kritischer Teil des Rollback-Skripts. Das Skript darf dabei keine Annahmen über die Namensgebung der Releases machen — es muss anhand der tatsächlich vorhandenen Verzeichnisse auf dem Server entscheiden. Der zuverlässigste Ansatz ist das Auflisten aller Release-Verzeichnisse in sortierter Reihenfolge und das Überspringen des aktuell aktiven Release.

Wenn das Tag-Format SemVer ist, lässt sich auch eine semantische Sortierung implementieren: sort -V sortiert nach Versionsnummern korrekt und stellt sicher, dass v1.9.0 vor v1.10.0 kommt. Diese Sortierung ist robuster als alphabetische Sortierung, die bei zweistelligen Minor-Versionen falsche Ergebnisse liefert. Das Skript gibt immer klar aus, welches Release als Rollback-Ziel ausgewählt wurde, bevor es den Wechsel durchführt.

6. Cache-Flush und Queue-Verhalten beim Rollback

Nach dem Symlink-Wechsel muss der Magento-Cache vollständig geleert werden. Das gilt auch dann, wenn das vorherige Release dieselben Cache-Keys verwendet hat — weil Redis möglicherweise Daten aus dem fehlerhaften Release gecacht hat, die mit dem alten Code inkompatibel sind. Ein bin/magento cache:flush nach dem Rollback ist Pflicht, kein optionaler Schritt.

Die Queue ist komplexer. Nachrichten, die bereits in RabbitMQ oder in der Magento-Queue liegen, wurden möglicherweise von Consumern des neuen Release eingestellt. Diese Nachrichten könnten mit dem alten Code nicht korrekt verarbeitet werden. Das Rollback-Skript sollte Queue-Consumer stoppen, bevor der Symlink gewechselt wird, und nach dem Rollback wieder starten. In Magento-Umgebungen mit Supervisor oder systemd sind die Consumer-Prozesse ohnehin durch Prozess-Manager gesteuert — diese müssen nach dem Rollback explizit neu gestartet werden, damit sie den neuen Anwendungspfad verwenden.

7. Rollback regelmäßig testen

Der wichtigste Satz in diesem Artikel ist: Ein Rollback, der nie getestet wurde, ist kein Rollback. Das Rollback-Skript muss auf Staging regelmäßig ausgeführt werden — nicht in einer simulierten Umgebung, sondern mit dem echten Skript gegen den echten Staging-Server. Das bedeutet: ein Release deployen, dann den Rollback-Job auslösen, dann verifizieren, dass der vorherige Stand wieder aktiv ist.

Dieser Test sollte Teil des regelmäßigen Team-Routinen sein und im Deploy-Checkliste dokumentiert. Idealerweise wird ein Chaos-Engineering-Ansatz gewählt: Einmal im Monat wird vor dem geplanten Deployment auf Staging ein Rollback-Test durchgeführt. Das Team sieht, wie lange der Rollback dauert, welche Schritte ausgeführt werden und ob der Verify-Job danach grün ist. Diese Übung ist günstiger als ein ungeplanter Rollback unter Produktionsdruck.

8. Rollback-Strategien im Vergleich

Es gibt verschiedene Rollback-Strategien, die unterschiedlich viel Vorbereitung erfordern und unterschiedliche Einschränkungen haben. Der Vergleich hilft bei der Entscheidung, welche Strategie für das eigene Magento-Projekt passt.

Strategie Dauer Voraussetzung Eignung
Symlink-Rollback < 1 Minute Release-Verzeichnis vorhanden Immer empfohlen
Neues Deployment (altes Tag) 5–15 Minuten Tag vorhanden, Pipeline grün Wenn kein Release-Dir. mehr da
DB-Rollback 30+ Minuten Backup vor dem Deploy Nur wenn DB-Migrationen Rollback erfordern
git revert + Deploy 15–30 Minuten Neuer Commit + neue Pipeline Wenn kein älteres Release vorhanden
Server-Snapshot 5–20 Minuten Snapshot vor dem Deploy Notfall ohne Release-Struktur

9. Zusammenfassung

Ein Rollback-Skript für Magento in GitLab ist kein optionales Feature, sondern ein Pflichtbestandteil jedes Deployment-Prozesses. Das Skript wechselt den current-Symlink auf das Vorgänger-Release, flusht den Cache, stoppt und startet Queue-Consumer und gibt klar aus, was passiert. Der zugehörige GitLab-Job ist manuell auslösbar aus der letzten Deploy-Pipeline und benötigt keine neue Pipeline.

Der Schlüssel zum erfolgreichen Rollback liegt in drei Dingen: Vorbereitung vor dem ersten Deployment, Testen auf Staging in regelmäßigen Abständen und klare Dokumentation, wer unter welchen Umständen den Rollback-Job auslösen darf. Ein Rollback, der nicht geübt wurde, ist im Störfall eine Wette — kein Plan.

Rollback-Skript für Magento — Das Wichtigste auf einen Blick

Kernmechanismus

Symlink-Wechsel auf Vorgänger-Release. Dauert weniger als eine Sekunde. Voraussetzung: Release-Verzeichnisse vorhanden.

Pflichtschritte

Maintenance-Mode an, Symlink wechseln, Cache flushen, Queue-Consumer neu starten, Maintenance-Mode aus. Reihenfolge einhalten.

GitLab-Integration

Manueller Job in rollback-Stage der Deploy-Pipeline. Keine neue Pipeline nötig. ROLLBACK_TARGET-Variable für spezifische Releases.

Testrhythmus

Mindestens monatlich auf Staging. Rollback-Test als fixer Teil der Deploy-Checkliste. Ungeübter Rollback ist kein echter Rollback.

10. Typische Fehler beim Rollback

Der häufigste Fehler ist das Vergessen des Cache-Flushes nach dem Symlink-Wechsel. Redis hält möglicherweise gecachte Objekte aus dem fehlerhaften Release, die mit dem alten Code inkompatibel sind. Ein Magento-System, das nach dem Rollback ohne Cache-Flush betrieben wird, verhält sich unvorhersehbar — manchmal korrekt, manchmal mit 500-Fehlern, die schwer zu diagnostizieren sind.

Ein zweiter Fehler ist die fehlende Überprüfung, ob das Rollback-Ziel existiert. Ein Rollback-Skript, das versucht, auf ein nicht mehr vorhandenes Release zu wechseln, und dabei einen halb abgeschlossenen Zustand hinterlässt, macht den Schaden schlimmer. Das Skript muss das Zielverzeichnis prüfen und bei Abwesenheit mit einem klaren Fehler abbrechen — bevor der aktuelle Symlink geändert wird. Die Reihenfolge ist entscheidend: erst prüfen, dann wechseln.

11. FAQ: Rollback-Skript für Magento in GitLab

1Wie lange dauert ein Symlink-Rollback?
Symlink-Wechsel unter einer Sekunde. Gesamt mit Maintenance-Mode, Cache-Flush und Queue-Neustart 30–120 Sekunden.
2Rollback ohne GitLab-Job möglich?
Ja, per direktem SSH-Zugriff. Aber der GitLab-Job protokolliert Zeitpunkt und Ausführenden — für die Nachvollziehbarkeit wichtig.
3Was passiert mit der Datenbank beim Rollback?
Nichts. Datei-Rollback berührt die DB nicht. Bei Releases mit DB-Migrationen braucht man eine separate Rollback-Strategie.
4Wer darf den Rollback auslösen?
Nur Maintainer — dieselbe Rolle, die auch Deployments auslösen darf. Über GitLab-Projektrollen und protected environments steuern.
5Rollback-Ziel-Release nicht mehr auf dem Server?
Fallback: Alte Release-Pipeline manuell neu starten. Oder Server-Snapshot vom Cloud-Provider. Retention-Policy verhindert dieses Problem.
6Queue-Consumer nach Rollback?
Mit Supervisor oder systemd neu starten. Consumer lesen Code über current-Symlink — nach Neustart verwenden sie automatisch den neuen (alten) Code.
7Maintenance-Mode beim Rollback nötig?
Ja, kurz für Symlink-Wechsel und Cache-Flush. Verhindert Requests auf inkonsistenten Zustand. Dauert nur 10–30 Sekunden.
8Rollback in anderer Pipeline auslösen?
Möglich über manuelle Pipeline-Triggerung. Einfacher: direkt aus der letzten Deploy-Pipeline den Rollback-Job auslösen.
9Rollback dokumentieren?
Automatisch durch GitLab-Job-Log + RELEASES.log auf dem Server + Slack-Benachrichtigung aus dem Job heraus.
10Rollback vs. Revert?
Rollback: sofortiger Code-Wechsel auf alten Stand ohne neuen Commit. Revert: neuer Commit der die Änderungen rückgängig macht, dann Deploy. Rollback ist schneller; Revert sauberer für die Historie.