CI/CD
.yml
GitLab · Deployer PHP · Magento · CI/CD
Deployer mit GitLab CI für Magento richtig kombinieren
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.

15 Min. Lesezeit Deployer · GitLab CI · Release-Struktur · Rollback Magento 2.4 · PHP 8.4 · GitLab 17+

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.

11. FAQ: Deployer mit GitLab CI für Magento

1Kann ich Deployer ohne GitLab CI verwenden?
Ja, Deployer kann direkt von der Kommandozeile gestartet werden. Die GitLab-Kombination bringt aber Pipeline-Kontrolle, Artefakt-Management und teamfähige Freigabeprozesse.
2Was passiert beim Rollback mit Datenbankmigrationen?
Deployer rollt nur Dateien zurück. Nicht rückwärtskompatible Migrationen müssen separat behandelt werden. Expand/Contract-Muster empfohlen.
3Wie viele Releases sollte ich behalten?
Mindestens fünf für Produktionssysteme. Erlaubt mehrere Rollback-Schritte hintereinander. Mehr als zehn nur bei ausreichend Speicherplatz.
4Muss PHP auf dem GitLab-Runner vorhanden sein?
Ja, Deployer ist ein PHP-Tool. Ein Docker-Image mit PHP und Deployer vorinstalliert ist die sauberste Lösung für den Deploy-Runner.
5Wie verwalte ich env.php mit Deployer?
Als Shared-Datei in deploy.php konfiguriert. Liegt einmalig unter shared/app/etc/env.php, wird in jeden Release per Symlink eingehängt.
6Deployer auf mehrere Server gleichzeitig?
Ja. Deployer unterstützt mehrere Hosts und parallele Deployments. Jeder Host kann eigene oder gemeinsame Task-Sequenzen erhalten.
7Static Content nicht erneut deployen?
Als CI-Artefakt bauen und mit dem Release synchronisieren. Kein erneutes setup:static-content:deploy auf dem Server nötig.
8dep deploy vs. dep rollback — was ist der Unterschied?
dep deploy baut ein neues Release mit allen Tasks. dep rollback schaltet nur den current-Symlink auf das vorherige Release, ohne Build-Schritte.
9Wo wird der Deployer-Befehl ausgeführt?
Auf dem GitLab-Runner, nicht auf dem Zielserver. Deployer verbindet sich per SSH mit dem Zielserver und führt dort serverseitige Kommandos aus.
10Deployer-Änderungen testen vor Production?
Mit einem dedizierten Staging-Host in Deployer und einer separaten Pipeline-Stage. Staging-Erfolg gibt die manuelle Freigabe für Production frei.