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.
Inhaltsverzeichnis
- 1. Das Promotion-Konzept: Artefakt befördern statt neu bauen
- 2. GitLab Environments: staging und production sauber trennen
- 3. Variable-Scopes für Staging und Production konfigurieren
- 4. Manuelle Freigaben und Approval-Gates in GitLab
- 5. Artefakte zwischen Stages weitergeben und wiederverwenden
- 6. Staging-Verifikation als Voraussetzung für Production
- 7. Neu-Build auf Production vs. Promotion im Vergleich
- 8. Magento-spezifische Schritte bei der Promotion
- 9. Rollback-Strategie nach fehlgeschlagener Promotion
- 10. Zusammenfassung
- 11. FAQ
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.