CI/CD
.yml
GitLab · Environments · Staging · Production · Magento
Staging → Production Promotion
mit GitLab Pipelines sauber bauen

Wer auf Production dasselbe baut wie auf Staging, testet in Wirklichkeit nicht das, was er auf Staging getestet hat. Die Promotion eines validierten Artefakts – statt eines Neu-Builds – ist das Fundament reproduzierbarer Deployments. GitLab Environments, manuelle Freigaben und korrekte Variable-Scopes machen diesen Prozess teamfähig und auditierbar.

13 Min. Lesezeit Environments · Artefakt-Promotion · Manuelle Freigabe · Rollback GitLab CI/CD · Magento 2 · Zero Downtime

1. Das Promotion-Konzept: Artefakt befördern statt neu bauen

Der grundlegende Fehler in vielen CI/CD-Setups: Staging und Production bauen dasselbe Quellcode-Commit, aber der Build-Prozess läuft zweimal unabhängig durch. Composer-Versionen können sich unterscheiden, wenn zwischen den Builds eine neue Paketversion veröffentlicht wurde. npm-Builds können unterschiedliche Output-Dateien erzeugen, wenn Node.js oder ein Build-Tool aktualisiert wurde. Das Ergebnis: Was auf Staging getestet wurde, ist nicht identisch mit dem, was auf Production landet – obwohl es sich um denselben Git-Hash handelt.

Das Promotion-Konzept löst dieses Problem durch ein einfaches Prinzip: Es wird einmal gebaut, und das resultierende Artefakt wird von Staging nach Production befördert. Der Deploy-Job auf Production verwendet dasselbe Paket, das auf Staging erfolgreich deployt und verifiziert wurde. Kein zweiter Composer-Install, kein zweiter npm-Build, kein zweites setup:di:compile. Das Artefakt ist die einzige Wahrheitsquelle – und es wird kontrolliert promoviert, nicht neu erzeugt.

In GitLab lässt sich dieses Konzept mit Artefakten, Package Registry oder einer einfachen Paketdatei umsetzen, die zwischen Jobs und Stages weitergegeben wird. Welche Methode man wählt, hängt von der Artefaktgröße und der Pipeline-Laufzeit ab. Entscheidend ist das Prinzip: Build einmal, deploy mehrfach.

2. GitLab Environments: staging und production sauber trennen

GitLab Environments sind mehr als Labels in der Pipeline-Ansicht. Sie definieren den Kontext eines Deployments und ermöglichen es, Variablen, Deployments und Freigaben pro Umgebung zu verwalten. Unter Deployments > Environments sieht man alle aktiven Deployments, den aktuellen Stand jeder Umgebung und die letzten erfolgreichen Releases. Für Staging und Production werden zwei separate Environments angelegt: staging und production.

Jeder Deploy-Job in der .gitlab-ci.yml bekommt ein environment:-Schlüsselwort. GitLab verknüpft den Job automatisch mit dem entsprechenden Environment und zeigt den Deployment-Status in der UI. Für production empfiehlt sich zusätzlich environment: action: start und der Einsatz von Protected Environments, die in den Projekteinstellungen unter Settings > CI/CD > Protected Environments konfiguriert werden. Dort legt man fest, welche Rollen (Maintainer, Owner) einen Deployment-Job in der Production-Umgebung auslösen dürfen.

stages:
  - build
  - test
  - package
  - deploy_staging
  - verify_staging
  - deploy_production
  - verify_production

variables:
  GIT_STRATEGY: fetch
  ARTIFACT_NAME: "magento-release-${CI_COMMIT_TAG:-${CI_COMMIT_SHORT_SHA}}.tar.gz"

# Build once — reuse artifact across all deploy stages
build:magento:
  stage: build
  image: php:8.4-cli
  script:
    - composer install --no-dev --prefer-dist --no-interaction --quiet
    - npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
    - npm run build --prefix app/design/frontend/Mironsoft/default/web/tailwind
    - bin/magento setup:di:compile
    # Package everything into a single tarball for promotion
    - tar -czf "$ARTIFACT_NAME" \
        vendor/ generated/ pub/static/ \
        app/code/ app/design/ app/etc/config.php
  artifacts:
    paths:
      - "*.tar.gz"
    expire_in: 7 days
  only:
    - main
    - tags

3. Variable-Scopes für Staging und Production konfigurieren

GitLab erlaubt es, Variablen mit einem Environment Scope zu versehen. Eine Variable DEPLOY_HOST mit dem Scope staging enthält den Staging-Hostname, dieselbe Variable mit dem Scope production enthält den Production-Hostname. Der Deploy-Job wählt automatisch den richtigen Wert basierend auf seinem environment:-Schlüsselwort. Das bedeutet: Die .gitlab-ci.yml enthält keine Umgebungsspezifischen Hostnamen oder Pfade – alles liegt in den Variablen.

Für Staging und Production getrennte Scopes zu setzen ist nicht optional, sondern Grundvoraussetzung für einen sicheren Promotion-Prozess. Wenn Staging und Production dieselbe DEPLOY_HOST-Variable ohne Scope teilen, deployt jeder Job auf denselben Server – oder schlimmer: der Production-Job deployt versehentlich auf Staging. Mit Environment-Scoped Variables ist dieses Risiko strukturell ausgeschlossen. Die GitLab-Dokumentation bezeichnet Variables ohne Scope als Wildcard (*), die für alle Environments gilt – das ist der Standardfall und sollte für umgebungsabhängige Konfiguration immer durch spezifische Scopes ersetzt werden.

4. Manuelle Freigaben und Approval-Gates in GitLab

Production-Deployments sollten niemals automatisch nach einem Staging-Deploy starten. Der Schritt von Staging nach Production ist eine bewusste Entscheidung, die von einer autorisierten Person bestätigt werden muss. GitLab bietet dafür when: manual auf Job-Ebene. Ein manueller Job erscheint in der Pipeline-Ansicht als Play-Button und wird nicht automatisch ausgeführt. Erst wenn jemand mit den notwendigen Rechten auf den Button klickt, startet der Job.

Für formellere Freigaben bietet GitLab Premium Protected Environments with required approvals: Mehrere Personen müssen den Deployment-Job genehmigen, bevor er startet. Auch ohne Premium lässt sich ein zweistufiges Muster bauen: Der Staging-Verify-Job muss erfolgreich abgeschlossen sein (needs: [verify:staging]), und der Production-Deploy-Job ist manuell. So ist strukturell sichergestellt, dass Production erst angeboten wird, wenn Staging grün ist, und erst nach manueller Bestätigung läuft. Das ist das einfachste und effektivste Freigabetor ohne Premium-Lizenz.

deploy:staging:
  stage: deploy_staging
  before_script:
    - eval $(ssh-agent -s)
    - ssh-add "$SSH_PRIVATE_KEY"
    - mkdir -p ~/.ssh && echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
  script:
    # Transfer artifact and run deploy script on staging server
    - scp "$ARTIFACT_NAME" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/"
    - ssh "$DEPLOY_USER@$DEPLOY_HOST" "bash -s $ARTIFACT_NAME" < scripts/deploy.sh
  environment:
    name: staging
    url: https://staging.mironsoft.de
  needs: [build:magento]

verify:staging:
  stage: verify_staging
  script:
    - curl --fail --max-time 10 "https://staging.mironsoft.de/health"
    - curl --fail --max-time 10 "https://staging.mironsoft.de/"
  environment:
    name: staging
  needs: [deploy:staging]

deploy:production:
  stage: deploy_production
  before_script:
    - eval $(ssh-agent -s)
    - ssh-add "$SSH_PRIVATE_KEY"
    - mkdir -p ~/.ssh && echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
  script:
    # Promote the same artifact — no rebuild on production
    - scp "$ARTIFACT_NAME" "$DEPLOY_USER@$DEPLOY_HOST:/tmp/"
    - ssh "$DEPLOY_USER@$DEPLOY_HOST" "bash -s $ARTIFACT_NAME" < scripts/deploy.sh
  environment:
    name: production
    url: https://mironsoft.de
  needs: [verify:staging]
  when: manual
  only:
    - tags

5. Artefakte zwischen Stages weitergeben und wiederverwenden

GitLab-Artefakte sind Dateien, die ein Job produziert und die nachfolgende Jobs desselben Pipelines-Laufs herunterladen können. Mit needs: [build:magento] stellt ein Deploy-Job sicher, dass er das Artefakt aus dem Build-Job erhält. Das funktioniert auch stageübergreifend: Der Production-Deploy-Job in Stage 6 kann das Artefakt aus Stage 1 direkt herunterladen, ohne dass es durch alle Zwischenstages durchgereicht werden muss.

Für große Artefakte – ein vollständiges Magento-Paket mit vendor, generated und static files kann mehrere hundert Megabyte groß sein – ist die Artefakt-Übertragung über die GitLab-API manchmal langsamer als eine direkte SCP-Übertragung auf den Server. Eine Alternative: Das Artefakt im Build-Job auf einem externen Storage (S3, GCS oder NFS) ablegen und im Deploy-Job von dort herunterladen. Die Artefakt-URL dient dann als Referenz, die zwischen Jobs geteilt wird. Der Vorteil: Das Artefakt bleibt auch nach Ablauf der GitLab-Artefakt-Retention verfügbar und kann für spätere Rollbacks genutzt werden.

6. Staging-Verifikation als Voraussetzung für Production

Ein Staging-Verify-Job ist mehr als ein Smoke Test – er ist das Qualitätstor zwischen Staging und Production. Was auf Staging verifiziert wurde, wird auf Production promoviert; was fehlschlägt, blockiert die Promotion. Für Magento-Projekte sollte der Staging-Verify mindestens folgende Prüfungen abdecken: HTTP-Statuscode des Frontends, Health-Endpoint, Magento-Cache-Status per SSH und eine Stichprobe kritischer Seiten (Startseite, Kategorie, Produkt, Checkout-Einstieg).

Wer mehr Sicherheit möchte, ergänzt automatisierte Browser-Tests mit Playwright oder Puppeteer gegen die Staging-URL als Teil des Verify-Jobs. Diese Tests laufen nach dem Deploy auf Staging und müssen vollständig grün sein, bevor der Production-Deploy-Job als manueller Trigger verfügbar wird. Dieses Muster garantiert, dass die Person, die auf den Production-Deploy-Button klickt, nicht auf Basis von Hoffnung entscheidet, sondern auf Basis von verifizierten Testergebnissen.

7. Neu-Build auf Production vs. Promotion im Vergleich

Die Gegenüberstellung zeigt, wo die praktischen Unterschiede zwischen einem Neu-Build direkt auf Production und einer echten Artefakt-Promotion liegen.

Kriterium Neu-Build auf Production Artefakt-Promotion Empfehlung
Reproduzierbarkeit Abhängig von Paket-Versionen zum Build-Zeitpunkt Identisches Artefakt wie auf Staging Promotion
Testvalidität Was getestet wurde, stimmt nicht mit dem überein, was deployt wird Was auf Staging grün war, kommt auf Production Promotion
Deploy-Dauer Langer Build-Schritt auf Production Nur Transfer und Entpacken Promotion schneller
Rollback-Basis Welche Version war es genau? Artefakt mit Tag-Referenz, jederzeit nachvollziehbar Promotion auditierbar
Serverbelastung Build-Prozess auf Produktionsserver Nur Entpacken und Symlink-Wechsel Promotion schonender

Der häufigste Einwand gegen das Promotion-Modell: Das Artefakt ist zu groß für die GitLab-Artefakt-Retention. Die Lösung ist nicht, auf Promotion zu verzichten, sondern das Artefakt auf externem Storage abzulegen und nur die Referenz weiterzugeben. Das ist ein Infrastrukturproblem, das sich lösen lässt – der Tausch von Reproduzierbarkeit gegen Bequemlichkeit lässt sich nicht rückgängig machen.

8. Magento-spezifische Schritte bei der Promotion

Wenn das Artefakt auf dem Production-Server entpackt ist, folgen Magento-spezifische Schritte, die sich von Staging unterscheiden können. Die env.php und die config.php aus den Shared-Verzeichnissen werden per Symlink eingebunden – nicht aus dem Artefakt überschrieben. Der Grund: env.php enthält datenbankspezifische Zugangsdaten und umgebungsabhängige Konfiguration, die auf Production anders ist als auf Staging.

Für Static Content gibt es zwei Ansätze bei der Promotion: Entweder wird der bereits auf Staging kompilierte Static Content aus dem Artefakt übernommen – was schnell ist, aber Thema-Pfade voraussetzt, die auf beiden Umgebungen identisch sind – oder setup:static-content:deploy läuft nach dem Symlink-Wechsel auf Production. Bei Hyvä Themes mit Tailwind-Build ist das Artefakt die bessere Wahl, weil der CSS-Output vom Build-Prozess abhängt und nicht vom Produktionsserver reproduziert werden sollte. Der Tailwind-Build läuft im Build-Job der Pipeline, und das Ergebnis ist Teil des Artefakts.

# Magento-specific steps executed on the target server after artifact deployment
# These run via SSH, not in the GitLab runner itself

# scripts/deploy.sh (called on remote server)
# Usage: bash deploy.sh <artifact_name>

# Example of the remote deployment sequence:
# 1. Extract artifact into new release directory
# 2. Link shared files (env.php, pub/media, var/log, var/session)
# 3. Run setup:upgrade if schema changes are expected
# 4. Flush cache — static content already in artifact from build stage
# 5. Switch symlink atomically
# 6. Run post-deploy verify commands

verify:production:
  stage: verify_production
  before_script:
    - eval $(ssh-agent -s)
    - ssh-add "$SSH_PRIVATE_KEY"
    - mkdir -p ~/.ssh && echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
  script:
    # HTTP checks
    - curl --fail --max-time 15 "https://mironsoft.de/health"
    - curl --fail --max-time 15 "https://mironsoft.de/"
    # Magento status via SSH
    - ssh "$DEPLOY_USER@$DEPLOY_HOST" \
        "cd $DEPLOY_PATH/current && bin/magento cache:status && bin/magento --version"
    # Check no maintenance mode is active
    - ssh "$DEPLOY_USER@$DEPLOY_HOST" \
        "test ! -f $DEPLOY_PATH/current/var/.maintenance.flag"
  environment:
    name: production
  needs: [deploy:production]
  only:
    - tags

9. Rollback-Strategie nach fehlgeschlagener Promotion

Wenn der Production-Verify-Job nach der Promotion fehlschlägt, muss sofort gerollt werden. Die Rollback-Strategie basiert auf der Release-Verzeichnisstruktur: Das vorherige Release-Verzeichnis ist noch vorhanden, und der Symlink-Wechsel zurück dauert Millisekunden. Ein rollback:production-Job mit when: manual ist in der Pipeline vorbereitet und kann sofort ausgelöst werden.

Nach dem Rollback folgt die Fehleranalyse: Was war am promotierten Artefakt anders als auf Staging? Häufige Ursachen sind Datenbankschema-Differenzen (Migration auf Staging, aber nicht auf Production), umgebungsabhängige Konfiguration, die nicht in der env.php abgebildet war, oder Caching-Zustände (Redis, Varnish), die auf Production anders sind als auf Staging. Wer den Fehler identifiziert hat, kann das Staging-Environment korrigieren, erneut verifizieren und eine neue Promotion starten – das nächste Mal mit besserem Verify-Abdeckungsgrad.

10. Zusammenfassung

Staging-to-Production Promotion ist kein Feature, das man irgendwann einbaut, wenn Zeit ist – es ist die Grundlage für reproduzierbare, testbare und auditierbare Deployments. Das Prinzip ist einfach: einmal bauen, das Ergebnis auf Staging verifizieren, dann dasselbe Paket auf Production befördern. GitLab unterstützt diesen Prozess mit Environments, Environment-Scoped Variables, manuellen Jobs und der Artefakt-Weitergabe zwischen Stages.

Die wichtigste Entscheidung ist die bewusste Trennung von Build und Deploy: kein Composer-Install auf dem Production-Server, kein npm-Build, kein setup:di:compile. Alles, was deterministisch im Build-Job reproduziert werden kann, gehört in den Build-Job – und das resultierende Artefakt ist das, was auf Production landet. Was auf Staging getestet wurde, kommt auf Production an. Das ist der Kern von Continuous Delivery für Magento-Projekte.

Staging-to-Production Promotion — Das Wichtigste auf einen Blick

Kernprinzip

Einmal bauen, das Artefakt auf Staging deployen und verifizieren, dann dasselbe Paket auf Production promovieren – kein Neu-Build.

Manuelle Freigabe

Production-Deploy-Job mit when: manual und needs: [verify:staging]. Production ist nur verfügbar, wenn Staging grün ist.

Environment-Scopes

DEPLOY_HOST, DEPLOY_USER und DEPLOY_PATH als scoped Variables – staging und production bekommen automatisch die richtigen Werte.

Rollback-Bereitschaft

rollback:production als manueller Job vorbereitet. Nach fehlgeschlagenem Verify sofort auslösbar – keine Improvisation im Störfall.

11. FAQ: Staging-to-Production Promotion in GitLab

1Warum auf Production nicht neu bauen?
Composer und npm-Builds sind nicht vollständig deterministisch. Zwischen zwei Durchläufen können Paketversionen wechseln, sodass das auf Production deployete Paket nicht identisch mit dem auf Staging getesteten ist.
2Was ist ein GitLab Environment?
Ein benannter Deployment-Kontext mit eigener Deployment-Historie, URL und variablen Scopes. Ermöglicht den aktuellen Stand jeder Umgebung in der GitLab-UI zu sehen und nachzuverfolgen.
3Production vor Staging deployen verhindern?
needs: [verify:staging] auf dem Production-Job. GitLab führt ihn nur aus, wenn Staging-Verify erfolgreich war. Mit when: manual ist zusätzlich manuelle Bestätigung nötig.
4Wie groß darf ein GitLab-Artefakt sein?
Auf gitlab.com bis zu 1 GB pro Job. Für sehr große Artefakte empfiehlt sich externer Storage mit Referenz-URL statt direkter GitLab-Artefakt-Übertragung.
5Denselben Deploy-Job für Staging und Production?
Ja, wenn die Unterschiede in Environment-Scoped Variables liegen. Beide Jobs nutzen dieselbe script-Sektion, bekommen durch den environment:-Namen aber unterschiedliche Variable-Werte.
6when: manual vs. Protected Environments?
when: manual erlaubt jedem mit Pipeline-Rechten den Start. Protected Environments (Premium) verlangen Genehmigung durch bestimmte Rollen. Für formelle Freigaben die stärkere Lösung.
7Muss setup:static-content:deploy auf Production laufen?
Nicht wenn der Static Content im Build-Artefakt enthalten ist. Bei Hyvä mit Tailwind empfohlen: Tailwind-Build und SCD laufen im CI-Build-Job, das Ergebnis ist Teil des Artefakts.
8Wie lange Artefakte aufbewahren?
Mindestens so lange, wie sinnvoll auf ein Release zurückgerollt werden kann – 7 bis 30 Tage sind üblich. Externer Storage ermöglicht längere Retention unabhängig von GitLab.
9Promotion testen bevor sie Production erreicht?
Den Promotion-Prozess auf einer produktionsähnlichen Umgebung üben. Wer nur auf Staging testet, prüft möglicherweise nicht die gleichen Servercharakteristika wie Production.
10Unterschiedliche Datenbankstände auf Staging und Production?
Datenbankmigrationen im Deploy-Prozess explizit berücksichtigen. setup:upgrade läuft nach dem Artefakt-Deploy. Expand-Contract-Muster für rückwärtskompatible Schemaänderungen verhindern Downtime.