vom Artefakt zum atomaren Release
Deployer PHP und GitLab CI/CD ergänzen sich für Magento-Deployments ideal: GitLab baut und testet, Deployer übernimmt die Release-Struktur, den Symlink-Wechsel und den Rollback-Pfad. Wer beide Werkzeuge richtig kombiniert, bekommt einen reproduzierbaren, teamfähigen Deployment-Prozess ohne Wartungsfenster-Roulette.
Inhaltsverzeichnis
- 1. Warum Deployer und GitLab CI zusammengehören
- 2. Aufgabenverteilung: was GitLab macht, was Deployer macht
- 3. Die GitLab-Pipeline als Einstiegspunkt
- 4. Deployer-Konfiguration für Magento
- 5. Release-Struktur und Shared-Verzeichnisse
- 6. Magento-spezifische Deploy-Schritte
- 7. Verify-Job nach dem Symlink-Wechsel
- 8. Rollback-Strategie mit Deployer
- 9. Direkte Tool-Gegenüberstellung
- 10. Zusammenfassung
- 11. FAQ
1. Warum Deployer und GitLab CI zusammengehören
Wer Magento-Deployments professionell betreiben will, stößt schnell auf eine Trennlinie: GitLab CI/CD ist hervorragend darin, Builds auszuführen, Tests zu starten und Artefakte zu erzeugen. Für die eigentliche Server-Orchestration — Release-Verzeichnisse anlegen, Symlinks atomisch wechseln, Shared-Pfade verwalten und Rollback in Sekunden durchführen — ist ein spezialisiertes Deploy-Tool wie Deployer besser geeignet. Die Kombination beider Werkzeuge schafft eine saubere Trennung der Verantwortlichkeiten und macht jeden Teil des Prozesses austauschbar, ohne den anderen zu beschädigen.
In der Praxis sieht man häufig entweder nur GitLab CI mit langen Bash-Blöcken im YAML oder nur Deployer, der lokal vom Entwicklerrechner aus gestartet wird. Beide Ansätze haben Schwächen: Der erste wird unlesbar und schwer wartbar, der zweite ist nicht reproduzierbar und entzieht sich der Pipeline-Kontrolle. Die Kombination bringt das Beste beider Welten zusammen und schafft einen Prozess, der im Team funktioniert.
Für Magento ist dieser Ansatz besonders wertvoll, weil das System viele Schritte erfordert, die exakt in der richtigen Reihenfolge ablaufen müssen: Composer-Installation, DI-Kompilierung, Static Content Deployment, Symlink-Operationen für Shared-Dateien, Setup-Upgrade und Cache-Flush. Deployer kennt diese Reihenfolge, protokolliert jeden Schritt und kann bei Fehlern auf den Vorgänger-Release zurückschalten, bevor ein Nutzer etwas bemerkt.
2. Aufgabenverteilung: was GitLab macht, was Deployer macht
Die Rollenverteilung zwischen GitLab CI und Deployer ist klar und sollte nicht verwischt werden. GitLab CI/CD übernimmt alles, was mit dem Repository-Zustand zusammenhängt: Code auschecken, Composer-Pakete installieren, NPM-Pakete laden, Frontend-Assets mit Tailwind bauen, DI-Kompilierung anstoßen, PHPStan und PHPUnit ausführen und das Ergebnis als Artefakt speichern. Am Ende der CI-Phase liegt ein vollständiges, gebautes Magento-Verzeichnis vor, das nicht mehr verändert werden muss.
Deployer übernimmt ab diesem Punkt: Es empfängt das Artefakt, legt auf dem Zielserver ein neues Release-Verzeichnis an, synchronisiert den Build-Stand dorthin, setzt die Shared-Symlinks für env.php, pub/media und var/log, führt setup:upgrade aus, deployt Static Content falls nötig, flusht den Cache und schaltet den Symlink auf das neue Release um. Dieser Symlink-Wechsel ist atomar aus Sicht des Webservers — was ihn zum Kern des Zero-Downtime-Modells macht.
3. Die GitLab-Pipeline als Einstiegspunkt
Die GitLab-Pipeline steuert, wann und für welche Branches oder Tags ein Deploy ausgelöst wird. Für Produktionssysteme sollte der Deploy-Job ausschließlich auf geschützten Tags oder dem main-Branch ausgeführt werden, und er sollte eine manuelle Freigabe erfordern. Das verhindert, dass jeder Merge automatisch auf Production landet. Die Pipeline-Konfiguration übergibt dem Deployer-Aufruf alle nötigen Variablen als Umgebungsvariablen, die zuvor in den GitLab-CI/CD-Settings hinterlegt wurden.
# .gitlab-ci.yml — Build and deploy Magento via Deployer
stages:
- build
- test
- deploy
- verify
variables:
COMPOSER_CACHE_DIR: ".cache/composer"
NPM_CONFIG_CACHE: ".cache/npm"
build:magento:
stage: build
image: php:8.4-cli
cache:
key: composer-${CI_COMMIT_REF_SLUG}
paths:
- .cache/composer/
script:
- apt-get update -qq && apt-get install -y -qq git unzip nodejs npm
- 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
- php bin/magento setup:di:compile
artifacts:
paths:
- vendor/
- generated/
- pub/static/
expire_in: 2 hours
deploy:production:
stage: deploy
image: php:8.4-cli
when: manual
only:
- tags
environment:
name: production
url: https://shop.example.com
script:
- apt-get update -qq && apt-get install -y -qq openssh-client rsync
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- vendor/bin/dep deploy production --no-interaction
4. Deployer-Konfiguration für Magento
Die Deployer-Konfigurationsdatei deploy.php im Repository-Root beschreibt den Zielserver, die Release-Einstellungen und die Aufgabenreihenfolge. Deployer bringt für Magento eine Standardkonfiguration mit, die über Recipes erweitert werden kann. Im Projektalltag lohnt es sich, eine eigene Basis-Konfiguration zu führen, die die Magento-spezifischen Schritte klar benennt und nichts implizit lässt. Besonders wichtig: die Liste der Shared-Dateien und -Verzeichnisse, die zwischen Releases geteilt werden.
Die Anzahl der aufbewahrten Releases sollte für Produktionssysteme mindestens fünf betragen, damit im Fehlerfall mehrere Schritte zurückgerollt werden können. Deployer löscht ältere Releases automatisch nach dem erfolgreichen Abschluss eines Deployments, sodass der Platzbedarf kontrolliert bleibt.
# deploy.php excerpt — Deployer configuration for Magento 2
# Keep 5 releases for rollback safety
set('keep_releases', 5);
set('shared_files', ['app/etc/env.php', 'app/etc/config.php']);
set('shared_dirs', ['pub/media', 'var/log', 'var/session', 'var/cache']);
set('writable_dirs', ['pub/media', 'var', 'pub/static', 'generated']);
# Host definition — reads secrets from environment variables
host('production')
->setHostname(getenv('DEPLOY_HOST'))
->setRemoteUser(getenv('DEPLOY_USER'))
->setDeployPath(getenv('DEPLOY_PATH'))
->set('branch', getenv('CI_COMMIT_TAG') ?: 'main');
# Custom task: flush Magento cache after symlink switch
task('magento:cache:flush', function () {
run('cd {{release_path}} && php bin/magento cache:flush');
});
# Define the deployment sequence
after('deploy:symlink', 'magento:cache:flush');
after('deploy:failed', 'deploy:unlock');
5. Release-Struktur und Shared-Verzeichnisse
Die Release-Struktur, die Deployer auf dem Server anlegt, ist das Herzstück des Zero-Downtime-Modells. Jedes Deployment erzeugt ein neues Verzeichnis unter releases/, das mit einem Timestamp benannt wird. Erst nach erfolgreicher Ausführung aller Deploy-Schritte wird der current-Symlink auf das neue Release umgestellt. Der Webserver zeigt immer auf current und bekommt den Wechsel nicht als Ausfallzeit mit — solange keine langen synchronen Datenbankmigrationen den Prozess blockieren.
Die Shared-Verzeichnisse liegen unterhalb von shared/ und werden in jeden Release als Symlink eingehängt. Das bedeutet: app/etc/env.php ist auf jedem Server einmalig vorhanden und wird nicht mit jedem Release überschrieben oder neu erzeugt. Dasselbe gilt für pub/media, var/log und var/session. Diese Trennung zwischen release-spezifischen und geteilten Daten ist eine der wichtigsten Designentscheidungen im gesamten Deployment-Prozess.
6. Magento-spezifische Deploy-Schritte
Magento erfordert nach dem Synchronisieren des Build-Stands mehrere Schritte, die in der richtigen Reihenfolge ablaufen müssen. Setup-Upgrade darf erst ausgeführt werden, nachdem die Shared-Symlinks gesetzt sind, weil das Kommando auf app/etc/env.php angewiesen ist. Static Content Deployment sollte im Build-Schritt der CI-Pipeline erfolgen und die Ausgabe als Artefakt mitgenommen werden, damit dieser zeitaufwändige Schritt nicht die eigentliche Deploy-Phase verlängert. Cache-Flush muss nach dem Symlink-Wechsel erfolgen, damit der neue Release-Stand sichtbar wird.
Für Teams, die Maintenance-Mode vermeiden wollen, ist die Reihenfolge entscheidend: Erst den neuen Release-Stand vorbereiten, dann den Symlink atomar wechseln, dann Cache flushen. Setup-Upgrade mit Datenbankmigrationen ist die einzige Phase, die potenziell einen kurzen Maintenance-Mode erfordert — aber nur, wenn die Migrationen nicht rückwärtskompatibel sind. Im Abschnitt über Datenbank-Strategien (Expand/Contract) lässt sich dieser Punkt vertiefen.
7. Verify-Job nach dem Symlink-Wechsel
Ein Deployment ohne Verifikation ist eine Wette. Der Verify-Job in der GitLab-Pipeline prüft unmittelbar nach dem Symlink-Wechsel, ob der neue Release-Stand erreichbar und funktionsfähig ist. Mindestens sollten ein HTTP-Health-Check und ein Magento-Cache-Status-Check ausgeführt werden. Wer mehr Sicherheit braucht, ergänzt Smoke-Tests für kritische Pfade wie Startseite, Kategorieseite und Checkout. Der Verify-Job läuft mit when: on_success nach dem Deploy-Job und entscheidet, ob das Deployment als erfolgreich gilt oder ein Rollback ausgelöst werden soll.
# Verify job — runs immediately after successful deploy
verify:production:
stage: verify
image: alpine:3.19
when: on_success
needs: ["deploy:production"]
script:
- apk add --no-cache curl openssh-client
# HTTP health check — expects 200 OK
- curl --fail --silent --max-time 15 https://shop.example.com/health
# Homepage must return HTTP 200
- curl --fail --silent --max-time 20 --output /dev/null https://shop.example.com/
# Check Magento cache status via SSH
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && echo "$SSH_KNOWN_HOSTS" > ~/.ssh/known_hosts
- ssh "$DEPLOY_USER@$DEPLOY_HOST"
"cd $DEPLOY_PATH/current && php bin/magento cache:status"
allow_failure: false
8. Rollback-Strategie mit Deployer
Deployer macht Rollback trivial: Der Befehl dep rollback production schaltet den current-Symlink auf den letzten erfolgreichen Release zurück. Das dauert Sekunden statt Minuten, weil keine Dateien kopiert werden müssen. Im Fehlerfall — wenn der Verify-Job fehlschlägt — sollte der Rollback-Job automatisch als nachgelagerter Job in der Pipeline ausgeführt werden. Damit ist der Rollback kein manueller Notfallprozess, sondern ein definierter Schritt der Pipeline.
Wichtig: Deployer speichert den Rollback-Pfad nur innerhalb der konfigurierten Anzahl aufbewahrter Releases. Wenn keep_releases auf fünf gesetzt ist und sechs Deployments hintereinander stattfinden, ist der älteste Release bereits gelöscht. Für Produktionssysteme sollte der Wert mindestens fünf betragen, damit auch nach mehreren Quick-Fixes ein stabiler Ausgangspunkt erreichbar ist. Datenbankmigrationen, die nicht rückwärtskompatibel sind, müssen separat betrachtet werden — der Datei-Rollback allein reicht dann nicht aus.
9. Direkte Tool-Gegenüberstellung
Für Teams, die noch zwischen verschiedenen Ansätzen abwägen, lohnt ein direkter Vergleich der wichtigsten Dimensionen. Die Entscheidung hängt stark vom Team-Kontext, der Server-Infrastruktur und dem gewünschten Automatisierungsgrad ab.
| Kriterium | Nur GitLab CI (Bash) | GitLab CI + Deployer | Vorteil |
|---|---|---|---|
| Release-Verwaltung | Manuell in Bash-Blöcken | Automatisch durch Deployer | Weniger Fehlerquellen, lesbare Config |
| Rollback-Geschwindigkeit | Minuten (manuell) | Sekunden (dep rollback) | Atomarer Symlink-Wechsel |
| Shared-Pfad-Verwaltung | Eigene Symlink-Logik | Deklarativ in deploy.php | Kein Vergessen von Shared-Links |
| Multi-Server-Support | Eigene SSH-Schleifen | Parallele Hosts in Deployer | Skaliert ohne Duplikat-Code |
| Lernkurve | Gering (nur Bash) | Moderat (PHP + Deployer-API) | Einmalige Investition |
Die Kombination aus GitLab CI und Deployer ist für Teams empfehlenswert, die mehr als einen Server betreiben, regelmäßig deployen und einen zuverlässigen Rollback-Pfad brauchen. Wer nur auf einen einzigen Server mit wenigen Deployments pro Monat deployed, kann mit einer sauber strukturierten Bash-Lösung beginnen und später zu Deployer migrieren, wenn die Komplexität wächst.
Mironsoft
GitLab CI/CD, Deployer und Magento-Deployment-Infrastruktur
Deployer und GitLab CI für Magento sauber aufsetzen?
Wir helfen dabei, GitLab CI/CD und Deployer PHP so zu kombinieren, dass Build, Release-Struktur, Verify-Jobs und Rollback-Pfad für Magento als belastbarer Prozess zusammenpassen.
Pipeline-Design
Build, Test, Deploy und Verify als klare Stages mit sauberen Übergaben
Deployer-Konfiguration
Shared-Pfade, Release-Rotation und Magento-Tasks sauber definieren
Rollback-Absicherung
Automatischer Rollback bei Verify-Fehler, ohne manuellen Eingriff
10. Zusammenfassung
Die Kombination aus Deployer PHP und GitLab CI/CD ergibt für Magento-Projekte einen Deployment-Prozess, der reproduzierbar, teamfähig und rollbackfähig ist. GitLab baut das Artefakt und steuert die Pipeline-Logik. Deployer übernimmt die serverseitige Release-Verwaltung: Release-Verzeichnisse anlegen, Shared-Symlinks setzen, Magento-Tasks ausführen und den Symlink atomar umschalten. Der Verify-Job prüft das Ergebnis, und der Rollback-Job kann bei Fehlern den vorherigen Stand in Sekunden wiederherstellen.
Das wichtigste Designprinzip bleibt: Nichts wird auf dem Produktionsserver gebaut. Das Artefakt entsteht kontrolliert in der CI-Umgebung und wird als unveränderlicher Stand auf den Server übertragen. Deployer übernimmt nur den Wechsel zwischen Ständen, nicht deren Erstellung. Diese Trennung ist der Schlüssel zu einem Deployment-Prozess, der auch unter Zeitdruck beherrschbar bleibt.
Deployer + GitLab CI für Magento — Das Wichtigste auf einen Blick
Aufgabentrennung
GitLab baut und testet, Deployer verwaltet Releases und schaltet Symlinks. Keine Vermischung der Verantwortlichkeiten.
Rollback in Sekunden
dep rollback production schaltet den current-Symlink auf den letzten stabilen Release. Kein Kopieren, kein Warten.
Shared-Pfade
env.php, pub/media, var/log und var/session werden deklarativ in deploy.php gelistet und als Symlinks in jeden Release eingehängt.
Verify-Job ist Pflicht
HTTP-Health-Check und Magento-Cache-Status nach dem Symlink-Wechsel. Ohne Verifikation ist kein Deployment abgeschlossen.