CI/CD
.yml
GitLab · Magento · CI/CD · Cheatsheet
GitLab + Magento Deployment Cheatsheet
Variablen, Jobs, Kommandos, Reihenfolge

Welche Variablen müssen gesetzt werden? Wie sind Jobs korrekt strukturiert? In welcher Reihenfolge werden Magento-Kommandos ausgeführt? Dieses Cheatsheet beantwortet diese Fragen kompakt und vollständig – als Nachschlagewerk für den Deployment-Alltag.

18 Min. Lesezeit Variablen · Job-Struktur · Magento-CLI · Reihenfolge · Rollback GitLab 16+ · Magento 2.4.8 · PHP 8.4

1. Pflicht-Variablen für jede Magento-Pipeline

Die CI/CD-Variablen einer GitLab-Pipeline sind der Konfigurationsvertrag zwischen Repository-Governance und tatsächlichem Deployment. Für Magento-Projekte gibt es eine Mindestmenge an Variablen, ohne die keine Pipeline sicher und reproduzierbar laufen kann. SSH_PRIVATE_KEY und SSH_KNOWN_HOSTS ermöglichen den sicheren Zugriff auf den Zielserver. DEPLOY_HOST, DEPLOY_USER und DEPLOY_PATH definieren, wo das Deployment landet. COMPOSER_AUTH enthält die Zugangsdaten für private Composer-Repositories wie Adobe Commerce. APP_ENV steuert, welche Magento-Konfiguration aktiv ist.

Alle Produktions-Secrets – SSH-Schlüssel, Datenbank-Passwörter, API-Keys – müssen als Protected und Masked markiert sein und einen Environment-Scope haben, der sie auf die jeweilige Umgebung beschränkt. Variablen, die in .gitlab-ci.yml direkt definiert sind, sollten keine Secrets enthalten, sondern nur unkritische Konfigurationswerte wie Cache-Verzeichnisse oder Retention-Werte. Dieser Trennung von Konfiguration und Secrets folgt das gesamte Cheatsheet.

# Required CI/CD variables — configure in Settings > CI/CD > Variables
# SSH access
# SSH_PRIVATE_KEY         — Protected, Masked, Scope: production
# SSH_KNOWN_HOSTS         — Protected, Scope: production

# Server target
# DEPLOY_HOST             — Protected, Scope: production (e.g. web01.mironsoft.de)
# DEPLOY_USER             — Protected, Scope: * (e.g. deploy)
# DEPLOY_PATH             — Protected, Scope: production (e.g. /var/www/magento)

# Magento configuration
# MAGENTO_ENV_FILE        — Protected, Masked, Scope: production
# COMPOSER_AUTH           — Protected, Masked, Scope: *
# APP_ENV                 — Not protected, Scope: production, Value: production

# Pipeline behavior
variables:
  GIT_STRATEGY: fetch
  GIT_DEPTH: "10"
  COMPOSER_CACHE_DIR: .cache/composer
  NPM_CONFIG_CACHE: .cache/npm
  RELEASE_RETENTION: "5"
  DEPLOY_TIMEOUT: "300"

2. Stages und ihre Bedeutung

Die Stage-Definition einer Pipeline ist keine Kosmetik, sondern die fachliche Reihenfolge des Deployment-Prozesses. Für Magento-Projekte haben sich sechs Stages bewährt: build, test, package, deploy, verify und rollback. Die Stage build erzeugt das Artefakt – Composer-Abhängigkeiten installieren, Frontend bauen, DI compilieren. Die Stage test führt PHPStan, PHPUnit und Lint-Checks aus. In package wird das Artefakt für die Übertragung vorbereitet. In deploy landet es auf dem Server und die Symlinks werden gesetzt. In verify werden Health-Checks und Smoke Tests ausgeführt. Die Stage rollback enthält einen manuellen Job, der im Fehlerfall aktiviert werden kann.

Wichtig ist die korrekte Abhängigkeitskette: Kein Deployment ohne erfolgreichen Build und bestandene Tests. Kein Verify ohne abgeschlossenes Deployment. Kein automatisches Rollback – das ist immer eine manuelle Entscheidung. Diese Reihenfolge ist in GitLab durch die Stage-Sequenz und die Job-Bedingungen when: on_success und when: manual abgebildet. Jede Abweichung davon muss bewusst und begründet sein.

3. Der Build-Job: was er leisten muss

Der Build-Job ist der kritischste Job der Pipeline. Er muss ein vollständiges, reproduzierbares Artefakt erzeugen, das ohne weitere Abhängigkeiten auf dem Zielserver deployed werden kann. Für Magento bedeutet das konkret: composer install --no-dev --prefer-dist --no-interaction installiert alle PHP-Abhängigkeiten. npm ci installiert Node-Abhängigkeiten reproduzierbar aus package-lock.json. Der Tailwind-Build erzeugt die kompilierten CSS-Dateien. bin/magento setup:di:compile erzeugt den generierten PHP-Code für Dependency Injection. Diese vier Schritte müssen in genau dieser Reihenfolge ausgeführt werden, weil jeder Schritt Ausgaben des vorherigen benötigt.

Das resultierende Artefakt umfasst die Verzeichnisse vendor/, generated/ und pub/static/. Es sollte mit einer kurzen Lebensdauer von einem Tag konfiguriert sein, damit alte Artefakte automatisch bereinigt werden. Der Build-Job darf keine Server-spezifischen Informationen enthalten – er muss in einer isolierten Umgebung laufen und dasselbe Ergebnis produzieren, egal wie oft er ausgeführt wird.

build:magento:
  stage: build
  image: php:8.4-cli
  cache:
    key: composer-$CI_COMMIT_REF_SLUG
    paths:
      - .cache/composer/
  before_script:
    - apt-get update -qq && apt-get install -y -qq git unzip nodejs npm libzip-dev
    - docker-php-ext-install zip
    - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
  script:
    # Install PHP dependencies from lock file
    - composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
    # Install Node dependencies reproducibly
    - npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
    # Build Tailwind CSS
    - npm run build --prefix app/design/frontend/Mironsoft/default/web/tailwind
    # Compile Dependency Injection (requires vendor/)
    - php bin/magento setup:di:compile
  artifacts:
    paths:
      - vendor/
      - generated/
      - pub/static/
    expire_in: 1 day
  rules:
    - if: '$CI_COMMIT_BRANCH == "main"'
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'

4. Der Deploy-Job: Artefakt auf den Server bringen

Der Deploy-Job überträgt das Build-Artefakt auf den Zielserver und wechselt den aktiven Release-Symlink. Die Übertragung erfolgt per rsync über SSH, weil rsync nur geänderte Dateien überträgt und damit deutlich schneller ist als ein vollständiges scp-Archiv. Der Symlink-Wechsel mit ln -sfn ist eine atomare Operation – für den Webserver gibt es keinen Moment, in dem der current-Link auf kein gültiges Verzeichnis zeigt.

Nach dem Symlink-Wechsel werden serverseitig die Magento-spezifischen Schritte ausgeführt: Shared-Dateien verlinken, Static Content deployen und Cache leeren. Diese Schritte laufen innerhalb einer SSH-Sitzung, damit ein Fehler die gesamte Operation abbricht. Der Deploy-Job gibt die RELEASE_ID als Artefakt weiter, damit der Rollback-Job im Fehlerfall weiß, auf welches Release er zurückschalten soll.

deploy:production:
  stage: deploy
  environment:
    name: production
    url: https://shop.mironsoft.de
  dependencies:
    - build:magento
  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
    - echo "$SSH_KNOWN_HOSTS" >> ~/.ssh/known_hosts
    - chmod 644 ~/.ssh/known_hosts
  script:
    - RELEASE_ID="$(date +%Y%m%d-%H%M%S)"
    - RELEASE_PATH="${DEPLOY_PATH}/releases/${RELEASE_ID}"
    # Create release directory
    - ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p ${RELEASE_PATH}"
    # Transfer build artifact
    - rsync -az --delete --exclude='.git' --exclude='var/' ./ "${DEPLOY_USER}@${DEPLOY_HOST}:${RELEASE_PATH}/"
    # Link shared files and switch symlink
    - ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "
        ln -sfn ${DEPLOY_PATH}/shared/app/etc/env.php ${RELEASE_PATH}/app/etc/env.php &&
        ln -sfn ${DEPLOY_PATH}/shared/pub/media ${RELEASE_PATH}/pub/media &&
        ln -sfn ${DEPLOY_PATH}/shared/var ${RELEASE_PATH}/var &&
        ln -sfn ${RELEASE_PATH} ${DEPLOY_PATH}/current
      "
    - echo "RELEASE_ID=${RELEASE_ID}" >> deploy.env
    # Cleanup old releases
    - ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "
        ls -1dt ${DEPLOY_PATH}/releases/*/ | tail -n +$((${RELEASE_RETENTION}+1)) | xargs rm -rf
      "
  artifacts:
    reports:
      dotenv: deploy.env
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v\d+\.\d+\.\d+$/'
      when: manual

5. Magento-Kommandos in der richtigen Reihenfolge

Die Reihenfolge der Magento-CLI-Kommandos nach dem Symlink-Wechsel ist entscheidend und darf nicht beliebig geändert werden. Zuerst werden die Datenbankmigrationen mit bin/magento setup:upgrade ausgeführt – das muss vor dem Static Content Deployment geschehen, weil Migrationen neue Layout-Blöcke und Konfigurationswerte hinzufügen können. Danach folgt bin/magento setup:static-content:deploy mit dem korrekten Locale-Parameter. Static Content muss deployed sein, bevor der Cache geleert wird, damit der neue Cache mit frischen Assets aufgebaut wird.

bin/magento cache:flush am Ende leert den gesamten Cache inklusive Block-Cache, Config-Cache und Layout-Cache. Für Zero-Downtime-Deployments sollte setup:upgrade nur dann ausgeführt werden, wenn tatsächlich neue Datenbankmigrationen vorhanden sind – überprüfbar mit bin/magento setup:db:status. Der Maintenance Mode sollte ausschließlich dann aktiviert werden, wenn nicht-kompatible Datenbankänderungen deployed werden, die gleichzeitig laufende Requests beeinflussen würden.

# Magento post-deploy commands — executed on server via SSH
# Run in this exact order to ensure correctness

# Step 1: Check if DB upgrade is needed
# bin/magento setup:db:status
# Exit code 0 = no upgrade needed, exit code 2 = upgrade needed

# Step 2: Conditional DB upgrade (only if needed)
# bin/magento setup:upgrade --keep-generated

# Step 3: Deploy static content for all locales
# bin/magento setup:static-content:deploy de_DE en_US -t Mironsoft/default -f

# Step 4: Flush cache (after static content is ready)
# bin/magento cache:flush

# Step 5: Warm up page cache for critical pages (optional)
# curl -s https://shop.mironsoft.de/ > /dev/null
# curl -s https://shop.mironsoft.de/customer/account/login > /dev/null

# Full sequence as SSH heredoc:
# ssh "$DEPLOY_USER@$DEPLOY_HOST" <<'SSH'
#   set -euo pipefail
#   cd "$DEPLOY_PATH/current"
#   STATUS=$(bin/magento setup:db:status; echo $?)
#   [[ "$STATUS" == "2" ]] && bin/magento setup:upgrade --keep-generated
#   bin/magento setup:static-content:deploy de_DE -t Mironsoft/default -f
#   bin/magento cache:flush
# SSH

6. Verify-Job: Deployment bestätigen

Ein Deployment ohne Verifikation ist technisch abgeschlossen, aber fachlich unvollständig. Der Verify-Job gibt der Pipeline einen klaren Endpunkt: Entweder der Shop antwortet korrekt, oder die Pipeline schlägt fehl und der Fehler ist sofort sichtbar. Smoke Tests für Magento umfassen mindestens drei Checks: HTTP 200 auf der Startseite, HTTP 200 auf der Login-Seite und einen Cache-Status-Check via Magento-CLI. Zusätzlich kann ein Health-Endpoint überprüft werden, der Datenbankverbindung, Redis und Elasticsearch/OpenSearch testet.

Der Verify-Job läuft automatisch nach dem Deploy-Job mit der Bedingung when: on_success. Schlägt er fehl, ist die Pipeline gescheitert und das Team wird benachrichtigt. Der Rollback-Job, der danach in der Stage rollback definiert ist, kann dann manuell ausgelöst werden. Dieses Muster – automatisches Verify, manuelles Rollback – ist für Magento-Produktionssysteme die empfohlene Variante, weil ein Rollback immer eine bewusste Entscheidung sein sollte und nie automatisch ausgelöst werden darf.

7. Rollback: der geübte Rückweg

Ein Rollback-Job, der erst im Ernstfall konfiguriert wird, ist kein echter Rollback – er ist ein Plan, der unter Druck entsteht. Der Rollback-Job muss von Anfang an in der Pipeline vorhanden sein, regelmäßig in Staging-Umgebungen getestet werden und klar dokumentiert sein. Er erhält die RELEASE_ID des vorherigen Releases als Umgebungsvariable aus den Job-Artefakten des Deploy-Jobs und schaltet den current-Symlink auf diesen Release zurück. Danach wird der Cache geleert.

Was der Rollback-Job explizit nicht leistet: Er macht Datenbankmigrationen nicht rückgängig. Wenn eine Migration ausgeführt wurde, die nicht mit dem alten Code kompatibel ist, löst ein Datei-Rollback allein das Problem nicht. Deshalb müssen Datenbankmigrationen nach dem Expand-Contract-Muster entwickelt werden – neue Spalten und Tabellen werden hinzugefügt, ohne alte zu entfernen, damit der alte Code noch funktioniert. Erst nach mehreren erfolgreichen Deployments mit dem neuen Code werden veraltete Datenbankstrukturen entfernt.

8. Häufige Fehler und ihre Ursachen

Der häufigste Fehler in Magento CI/CD-Pipelines ist das Ausführen von bin/magento setup:di:compile auf dem Produktionsserver statt im Build-Job. Das verursacht mehrere Probleme gleichzeitig: Der Compile-Vorgang dauert mehrere Minuten, während denen der Shop entweder im Maintenance Mode ist oder mit altem Code läuft. Außerdem ist das Ergebnis möglicherweise nicht reproduzierbar, weil die Server-Umgebung von der Build-Umgebung abweichen kann. Die DI-Kompilierung gehört ausschließlich in den Build-Job auf dem Runner.

Ein weiterer häufiger Fehler betrifft pub/static/: Wer vergisst, das Static-Content-Verzeichnis vor dem Deployment zu bereinigen, riskiert, dass alte CSS- und JS-Dateien mit neuen PHP-Templates gemischt werden. Das korrekte Muster: Im Build-Job das Verzeichnis bereinigen, Static Content deployen und das Ergebnis als Artefakt übertragen. Auf dem Server niemals setup:static-content:deploy ausführen, wenn das Verzeichnis bereits durch den Build-Artefakt befüllt wurde – das würde die Artefakt-Inhalte überschreiben.

Fehler Symptom Ursache Korrekte Lösung
DI-Compile auf Server Langer Ausfall, Race Conditions setup:di:compile im Deploy-Skript Nur im Build-Job ausführen
Veraltetes Static Content JS/CSS passt nicht zu PHP-Templates pub/static/ nicht bereinigt Im Build-Job bereinigen, Artefakt nutzen
Fehlende env.php Magento startet nicht Shared-Link nicht gesetzt env.php immer aus shared/ verlinken
Kein Rollback-Test Rollback schlägt im Ernstfall fehl Nie in Staging geübt Rollback monatlich in Staging testen
Zu viele Releases Disk voll auf Server RELEASE_RETENTION nicht gesetzt Cleanup nach Deployment ausführen

9. Jobs im Vergleich: häufige Varianten

In der Praxis gibt es für dieselbe Aufgabe oft mehrere Varianten in verschiedenen Pipelines. Die Wahl der richtigen Variante hängt von den konkreten Anforderungen ab – Sicherheit, Geschwindigkeit, Reproduzierbarkeit und Wartbarkeit. Für Magento-Projekte gibt es einige klare Empfehlungen, die sich aus den Eigenschaften von Magento ergeben.

Der wichtigste Grundsatz bleibt: Was auf dem Produktionsserver ausgeführt werden muss, sollte minimal sein. Jedes Kommando, das auf dem Server läuft, verlängert das Deployment-Fenster und erhöht das Fehlerrisiko. Das Ziel ist, auf dem Server nur noch den Symlink zu wechseln, die Shared-Dateien zu verlinken und den Cache zu leeren. Alles andere – Composer, npm, DI-Compile, Static-Content – gehört in den Build-Job auf dem Runner.

10. Zusammenfassung

Das GitLab Magento Deployment Cheatsheet deckt die wichtigsten Aspekte einer sicheren und reproduzierbaren Pipeline ab: Variablen mit korrekten Scopes und Flags, eine klare Stage-Struktur, ein vollständiger Build-Job, ein sauberer Deploy-Job mit Symlink-Wechsel, die korrekte Reihenfolge der Magento-Kommandos, ein Verify-Job und ein geübter Rollback-Pfad. Diese Bausteine sind nicht optional – sie sind die Mindestanforderung für ein produktionstaugliches Deployment-System.

Die häufigsten Fehler entstehen nicht durch Unkenntnis der einzelnen Kommandos, sondern durch fehlende Klarheit über die Reihenfolge und die Aufteilung zwischen Build-Job und Server-Operationen. Wer diese Trennung konsequent einhält, hat einen Deployment-Prozess, der reproduzierbar, nachvollziehbar und im Fehlerfall schnell korrigierbar ist. Der Rollback-Test in Staging ist dabei genauso wichtig wie der Deploy-Test auf Production – er ist der Beweis, dass der Rückweg wirklich funktioniert.

GitLab Magento Deployment Cheatsheet — Das Wichtigste auf einen Blick

Variablen

SSH_PRIVATE_KEY, DEPLOY_HOST, COMPOSER_AUTH als Protected + Masked + Scoped. Unkritische Werte direkt in .gitlab-ci.yml.

Build-Job

Composer, npm, Tailwind-Build und setup:di:compile ausschließlich im Build-Job. Nie auf dem Produktionsserver.

Deploy-Reihenfolge

Artefakt übertragen → Shared-Dateien verlinken → Symlink wechseln → Magento-Kommandos ausführen → Cache leeren.

Rollback

Immer manuell, nie automatisch. RELEASE_ID aus Deploy-Artefakten, Symlink zurückschalten, Cache leeren. Regelmäßig in Staging testen.

11. FAQ: GitLab Magento Deployment Cheatsheet

1Welche Variablen sind Pflicht?
SSH_PRIVATE_KEY, SSH_KNOWN_HOSTS, DEPLOY_HOST, DEPLOY_USER, DEPLOY_PATH, COMPOSER_AUTH und APP_ENV. Alle Secrets Protected + Masked + Scoped.
2DI-Compile nicht auf dem Server?
Dauert Minuten, nicht reproduzierbar auf Server. Ausschließlich im Build-Job auf dem Runner ausführen und als Artefakt übertragen.
3Reihenfolge Magento-Kommandos?
1. setup:upgrade (nur wenn nötig), 2. setup:static-content:deploy, 3. cache:flush. Static Content vor Cache-Flush – nicht umgekehrt.
4Wann Maintenance Mode aktivieren?
Nur bei nicht-kompatiblen DB-Änderungen. Bei Expand-Contract-Migrationen nicht notwendig. So selten wie möglich verwenden.
5Wie funktioniert der Rollback?
RELEASE_ID aus Deploy-Artefakten, Symlink zurückschalten, Cache leeren. Immer manuell ausgelöst, nie automatisch. Regelmäßig in Staging testen.
6Was gehört ins Build-Artefakt?
vendor/, generated/, pub/static/. Alles aus Composer, npm und setup:di:compile. Lebensdauer: 1 Tag, damit alte Artefakte automatisch bereinigt werden.
7cache:flush vs. cache:clean?
cache:flush leert alle Backends vollständig. cache:clean invalidiert spezifische Typen. Nach Deployment immer cache:flush für sauberen Neustart.
8Wie viele Releases aufbewahren?
Mindestens 3, empfohlen 5. Genug für Rollbacks, nicht so viele, dass Disk-Space zum Problem wird. RELEASE_RETENTION-Variable steuert den Cleanup.
9Was prüft der Verify-Job?
HTTP 200 auf Startseite und Login-Seite, Cache-Status via Magento-CLI. Optional: Health-Endpoint für DB, Redis und Elasticsearch.
10static-content:deploy nach Symlink-Wechsel?
Nur wenn nicht bereits durch Build-Artefakt befüllt. Empfehlung: im Build-Job deployen und als Artefakt übertragen – schneller und reproduzierbarer.