Build, Test, Package, Deploy, Verify
Eine .gitlab-ci.yml, die nur drei Jobs hat und keine Stages definiert, ist kein Deployment-Prozess – sie ist ein Skript, das irgendwann bricht. Wer Magento sauber deployt, braucht eine vollständige Pipeline-Struktur: reproduzierbare Build-Artefakte, definierte Freigaben, serverseitige Release-Verzeichnisse, kontrollierte Magento-Schritte und einen fachlich abgeschlossenen Verify-Job.
Inhaltsverzeichnis
- 1. Warum eine vollständige Pipeline-Struktur nötig ist
- 2. Stages definieren: die logische Reihenfolge des Deployments
- 3. Der Build-Job: Artefakte statt Serverzustand
- 4. Der Test-Job: Qualitätssicherung vor dem Deployment
- 5. Der Package-Job: Artefakt versiegeln und signieren
- 6. Der Deploy-Job: Release-Wechsel auf dem Zielserver
- 7. Der Verify-Job: fachlicher Abschluss der Pipeline
- 8. Rollback: der geübte Rückweg
- 9. Pipeline-Muster im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Warum eine vollständige Pipeline-Struktur nötig ist
Eine .gitlab-ci.yml für Magento ist kein technisches Detail am Rande des Projekts, sondern das zentrale Dokument des gesamten Deployment-Prozesses. Sie definiert, was in welcher Reihenfolge passiert, wer eine Freigabe erteilt, welche Artefakte erzeugt werden und wie das System nach einem fehlgeschlagenen Deploy zurückgesetzt wird. Wer diese Datei als Sammlung loser Befehle behandelt, baut ein System, das bei jedem abweichenden Release-Fall versagt – nicht wegen der Technologie, sondern wegen fehlender Prozessstruktur.
In Magento-Projekten ist die Pipeline-Struktur besonders kritisch, weil mehrere voneinander abhängige Systeme beteiligt sind: Composer-Abhängigkeiten, generierter DI-Code, kompilierte Frontend-Assets, Datenbankmigrationen, Static Content, Shared-Dateien und Cache-Schichten. Wenn diese Schritte nicht in einer klaren Reihenfolge mit definierten Abhängigkeiten ausgeführt werden, entsteht ein Deployment, das zufällig funktioniert – aber nicht nachvollziehbar.
Das Ziel einer vollständigen .gitlab-ci.yml ist nicht, jeden möglichen Fall abzudecken, sondern den Standardpfad so explizit zu machen, dass Abweichungen sofort sichtbar werden. Eine Pipeline, die einen Fehler im Build-Job transparent meldet, ist wertvoller als eine Pipeline, die still bis zum Deploy-Job läuft und dann auf Production bricht.
2. Stages definieren: die logische Reihenfolge des Deployments
Die stages-Deklaration am Anfang der .gitlab-ci.yml ist mehr als Dokumentation – sie legt fest, in welcher Reihenfolge Jobs ausgeführt werden und welche Stage abgeschlossen sein muss, bevor die nächste beginnt. Für Magento empfiehlt sich eine Struktur aus mindestens sechs Stages: build, test, package, deploy, verify und rollback. Diese Reihenfolge spiegelt den tatsächlichen Ablauf des Deployments wider und macht ihn für das gesamte Team sichtbar.
Die variables-Sektion am Anfang der Datei definiert projektweite Einstellungen wie Cache-Verzeichnisse, Git-Strategie und Standardwerte. Diese Werte werden von allen Jobs geerbt und können auf Job-Ebene überschrieben werden. Eine klare Trennung zwischen Variablen, die in der YAML-Datei stehen dürfen, und Variablen, die als CI/CD-Variable in GitLab hinterlegt sein müssen, ist Pflicht – Secrets dürfen niemals in der YAML-Datei selbst stehen.
# .gitlab-ci.yml — Complete Magento pipeline structure
stages:
- build
- test
- package
- deploy
- verify
- rollback
# Global pipeline variables (non-secret)
variables:
GIT_STRATEGY: fetch
GIT_DEPTH: "10"
COMPOSER_CACHE_DIR: ".cache/composer"
NPM_CONFIG_CACHE: ".cache/npm"
MAGENTO_LOCALE: "de_DE"
RELEASE_RETENTION: "5"
DEPLOY_TIMEOUT: "300"
# Reusable SSH setup anchor
.ssh_setup: &ssh_setup
before_script:
- 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
Die include-Direktive erlaubt es, die Pipeline auf mehrere Dateien aufzuteilen und gemeinsame Job-Templates in eigenen Dateien zu pflegen. Für Magento-Projekte mit mehreren Umgebungen bietet sich eine Trennung in eine gemeinsame Basis und umgebungsspezifische Overrides an. Anchors und YAML-Merging (<<: *anchor) reduzieren Wiederholungen innerhalb einer Datei, lösen aber das Problem der dateiübergreifenden Wiederverwendung nicht – dafür ist include zuständig.
3. Der Build-Job: Artefakte statt Serverzustand
Der Build-Job ist das Herzstück der reproduzierbaren Pipeline. Er führt alle Schritte aus, die notwendig sind, um aus dem Repository-Inhalt ein vollständiges, deployfähiges Artefakt zu erzeugen – ohne Abhängigkeit vom Zustand eines bestimmten Servers. Das bedeutet: composer install mit --no-dev und --prefer-dist, der Frontend-Build mit npm und Tailwind CSS, sowie setup:di:compile für die Magento Dependency Injection.
Artefakte werden über die artifacts-Sektion des Jobs definiert. GitLab übergibt diese Dateien automatisch an nachfolgende Jobs in der Pipeline. Die Auflistung der Artefakt-Pfade muss präzise sein: zu wenige Pfade bedeuten, dass nachfolgende Jobs auf fehlende Dateien treffen; zu viele bedeuten, dass unnötig große Artefakte zwischen Jobs übertragen werden. Das Ablaufdatum (expire_in) verhindert, dass alte Artefakte den Speicher des GitLab-Servers belasten.
# Build stage — produces all deployment artifacts from source
build:magento:
stage: build
image: php:8.4-cli
cache:
key: "${CI_COMMIT_REF_SLUG}-composer"
paths:
- .cache/composer/
policy: pull-push
before_script:
- apt-get update -qq && apt-get install -y -qq git unzip libzip-dev
- docker-php-ext-install zip
- curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
- node --version && npm --version
script:
# Install PHP dependencies without dev packages
- composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
# Build Tailwind CSS assets
- npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
- npm run build --prefix app/design/frontend/Mironsoft/default/web/tailwind
# Compile Magento DI (generates interceptors and factories)
- bin/magento setup:di:compile
# Deploy static content for configured locales
- bin/magento setup:static-content:deploy "$MAGENTO_LOCALE" -f --jobs=4
artifacts:
name: "magento-build-${CI_COMMIT_SHORT_SHA}"
paths:
- vendor/
- generated/
- pub/static/
- app/etc/config.php
exclude:
- vendor/**/.git
expire_in: 1 day
only:
- main
- /^release\/.*/
4. Der Test-Job: Qualitätssicherung vor dem Deployment
Der Test-Job läuft nach dem Build-Job und hat Zugriff auf dessen Artefakte. Er führt statische Code-Analysen und automatische Tests aus, die auf dem gebauten Code – nicht auf dem Repository-Rohzustand – basieren. Das ist wichtig, weil manche Fehler erst nach setup:di:compile sichtbar werden: falsch typisierte Constructor-Parameter, fehlende Klassen in generated/ oder Plugin-Konflikte, die erst zur Compile-Zeit aufgedeckt werden.
Die wichtigsten Test-Jobs für Magento sind PHPStan mit Magento-spezifischen Regeln, PHPCS mit dem Magento-Coding-Standard und Unit-Tests mit PHPUnit. PHPStan auf Level 6 oder höher findet Typ-Fehler, die in einem typisierten PHP-8.4-Projekt keine Ausnahme mehr sein dürfen. PHPCS stellt sicher, dass neuer Code den Magento-Standards entspricht und keine offensichtlichen Qualitätsprobleme eingebracht werden. All diese Checks sollten mit einem Non-Zero-Exit-Code fehlschlagen, damit die Pipeline bei Verstößen blockiert wird.
5. Der Package-Job: Artefakt versiegeln und signieren
Der Package-Job bündelt die Build-Artefakte zu einem einzelnen, versiegelten Paket, das in den Deploy-Job übertragen wird. Für Magento empfiehlt sich ein tar.gz-Archiv, das alle notwendigen Verzeichnisse enthält und mit einer Checksumme (SHA-256) versehen wird. Diese Checksumme ermöglicht es, die Integrität des Pakets vor dem Deployment zu verifizieren und sie im Nachhinein nachzuweisen.
Im Package-Job werden außerdem Metadaten erzeugt: Release-ID (Timestamp-basiert oder aus dem Git-Tag), Commit-SHA, Branch-Name und Pipeline-ID. Diese Metadaten werden in einer release.json-Datei im Paket abgelegt und ermöglichen es, auf dem Server jederzeit nachzuvollziehen, aus welchem Pipeline-Lauf ein bestimmter Release stammt. Das ist bei Rollbacks und Incident-Analysen unverzichtbar.
6. Der Deploy-Job: Release-Wechsel auf dem Zielserver
Der Deploy-Job überträgt das Paket auf den Zielserver und wechselt den aktuellen Release-Symlink. Er ist bewusst als when: manual für Production konfiguriert – das erzwingt eine explizite Freigabe durch eine autorisierte Person, bevor Code auf der produktiven Umgebung aktiviert wird. Für Staging kann der Job automatisch laufen, sobald Test und Package erfolgreich abgeschlossen sind.
Der eigentliche Deployment-Prozess folgt dem Symlink-Modell: Das neue Release wird in ein timestampbasiertes Verzeichnis unter releases/ entpackt, Shared-Dateien (env.php, pub/media, var/log) werden als Symlinks eingehängt, und erst wenn alle Vorbereitungen abgeschlossen sind, wird der current-Symlink atomar auf das neue Release umgestellt. Die Webserver-Konfiguration zeigt immer auf current – der Symlink-Wechsel ist die eigentliche Zero-Downtime-Operation.
# Deploy stage — transfers artifact and switches release symlink
deploy:production:
stage: deploy
<<: *ssh_setup
environment:
name: production
url: https://shop.example.com
script:
- |
# Calculate release identifier from pipeline timestamp
RELEASE_ID=$(date +%Y%m%d-%H%M%S)
RELEASE_PATH="${DEPLOY_PATH}/releases/${RELEASE_ID}"
# Transfer build artifact to release directory
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p ${RELEASE_PATH}"
rsync -az --delete \
--exclude=".git" \
--exclude="var/cache" \
./ "${DEPLOY_USER}@${DEPLOY_HOST}:${RELEASE_PATH}/"
# Link shared paths and activate release on server
ssh "${DEPLOY_USER}@${DEPLOY_HOST}" bash << 'REMOTE'
set -euo pipefail
cd "${RELEASE_PATH}"
# Link persistent shared files into new release
ln -sfn "${DEPLOY_PATH}/shared/app/etc/env.php" app/etc/env.php
ln -sfn "${DEPLOY_PATH}/shared/app/etc/config.php" app/etc/config.php
ln -sfn "${DEPLOY_PATH}/shared/pub/media" pub/media
ln -sfn "${DEPLOY_PATH}/shared/var/log" var/log
ln -sfn "${DEPLOY_PATH}/shared/var/session" var/session
# Run database migrations (only if schema changes exist)
bin/magento setup:upgrade --keep-generated
# Flush all cache types before activating
bin/magento cache:flush
# Atomic symlink switch — this is the zero-downtime moment
ln -sfn "${RELEASE_PATH}" "${DEPLOY_PATH}/current"
# Remove releases exceeding retention limit
ls -dt "${DEPLOY_PATH}"/releases/*/ | tail -n +$((RELEASE_RETENTION + 1)) | xargs rm -rf
REMOTE
when: manual
only:
- main
- tags
7. Der Verify-Job: fachlicher Abschluss der Pipeline
Der Verify-Job schließt die Pipeline fachlich ab. Ein Deploy-Job, der mit Exit-Code 0 endet, bedeutet nur, dass die SSH-Befehle erfolgreich ausgeführt wurden – nicht, dass der Shop tatsächlich korrekt funktioniert. Der Verify-Job führt HTTP-Checks gegen den Live-Shop aus, prüft den Cache-Status auf dem Server und verifiziert, dass kritische Seiten ohne Fehler antworten. Wenn der Verify-Job fehlschlägt, ist das ein Signal, dass sofort der Rollback-Job ausgeführt werden muss.
Mindestens drei Prüfungen sollte der Verify-Job enthalten: Ein HTTP-200-Check gegen den Health-Endpoint, ein Check der Startseite und ein Blick in das Magento-Fehlerlog auf dem Server. Erweitert werden kann der Job durch Checks gegen kritische Kategorieseiten, den Checkout-Flow und die Admin-Oberfläche. Je mehr Checks im Verify-Job vorhanden sind, desto früher wird ein Problem nach einem Deployment erkannt – bevor Kunden es melden.
8. Rollback: der geübte Rückweg
Der Rollback-Job ist kein Notfallplan, sondern ein regulärer Bestandteil der Pipeline. Er wird als when: manual konfiguriert und kann jederzeit nach einem Deploy-Job ausgeführt werden – idealerweise innerhalb von Sekunden, nicht Minuten. Der Rollback-Mechanismus ist simpel: Der current-Symlink wird auf das vorangegangene Release-Verzeichnis zurückgestellt, der Cache wird geleert, und der Verify-Job läuft erneut.
Das Rollback-Modell funktioniert jedoch nur dann zuverlässig, wenn Datenbankmigrationen abwärtskompatibel sind – ein Rollback des Codes bei einer inkompatiblen Datenbank-Schemaänderung ist kein echtes Rollback. Deshalb sollte setup:upgrade in der Pipeline immer das Expand-Contract-Muster einhalten: Neue Spalten werden zuerst optional, alte Spalten erst in einem späteren Release entfernt. So bleibt der Rollback-Pfad für Dateiänderungen immer offen.
9. Pipeline-Muster im Vergleich
Der Unterschied zwischen einer improvisierten und einer strukturierten .gitlab-ci.yml für Magento zeigt sich besonders deutlich, wenn eine Pipeline zum ersten Mal unter ungewohnten Bedingungen läuft – ein neuer Entwickler, ein neuer Server oder ein abweichender Branch. Strukturierte Pipelines sind explizit genug, um in diesen Situationen zuverlässig zu funktionieren.
| Aspekt | Improvisierte Pipeline | Strukturierte Pipeline | Auswirkung |
|---|---|---|---|
| Stage-Reihenfolge | Build und Deploy in einem Job | Explizite stages-Deklaration | Sichtbare Abhängigkeiten und Freigabepunkte |
| Artefakte | Kein artifact, Build auf Server | Artefakt aus Build-Job, übergeben | Reproduzierbarkeit und Trennung Build/Deploy |
| Freigabe Production | Automatisch bei jedem Push | when: manual für Production | Kontrollierter Deploy, kein versehentlicher Release |
| Verify-Schritt | Keiner vorhanden | HTTP-Check + Cache-Check + Log-Check | Fehler erkannt bevor Kunden betroffen sind |
| Rollback | Manuell, kein geübter Pfad | Rollback-Job, when: manual | Rückweg in Sekunden, nicht Stunden |
Die Tabelle zeigt, dass die Unterschiede nicht in der Komplexität einzelner Befehle liegen, sondern in der Explizitheit des Prozesses. Eine strukturierte .gitlab-ci.yml kostet mehr Arbeit beim initialen Design, aber sie verhindert die hektischen Notoperationen, die bei improvisierten Pipelines regelmäßig anfallen. Der Return on Investment liegt darin, dass jeder Deploy planbar und nachvollziehbar abläuft – nicht nur der erste.
10. Zusammenfassung
Eine komplette .gitlab-ci.yml für Magento besteht aus sechs Stages, die den tatsächlichen Ablauf des Deployments widerspiegeln: Build erzeugt reproduzierbare Artefakte aus dem Repository. Test prüft den gebauten Code gegen statische Analysen und Unit-Tests. Package bündelt und versiegelt das Artefakt. Deploy überträgt das Paket, wechselt den Symlink und führt Magento-spezifische Schritte aus. Verify prüft den Shop nach dem Deployment. Rollback stellt den vorigen Zustand wieder her, wenn ein Problem erkannt wird.
Die wichtigste Praxisregel: Nichts, was auf Production läuft, darf in der Pipeline implizit bleiben. Jede Entscheidung – welche Artefakte erzeugt werden, wann ein Deployment freigegeben wird, welche Checks nach dem Deploy laufen – muss in der YAML-Datei explizit stehen. Nur dann ist die Pipeline ein zuverlässiger Deployment-Standard und kein fragiles Konstrukt, das nur unter optimalen Bedingungen funktioniert.
Komplette .gitlab-ci.yml für Magento — Das Wichtigste auf einen Blick
Stage-Reihenfolge
build → test → package → deploy → verify → rollback. Jede Stage muss abgeschlossen sein, bevor die nächste beginnt. Keine Shortcuts in Production.
Artefakt-Prinzip
Der Build-Job erzeugt einmal ein vollständiges Artefakt. Alle nachfolgenden Jobs verwenden dieses Artefakt – kein zweiter Build auf dem Server.
Freigabe & Rollback
Production-Deploy immer als when: manual. Rollback-Job muss geübt und in Sekunden ausführbar sein – nicht improvisiert im Störfall.
Verify als Pflicht
Ohne Verify-Job ist die Pipeline technisch, aber nicht fachlich abgeschlossen. HTTP-Check, Cache-Check und Log-Check sind Minimalanforderungen.