Artefakte, Reproduzierbarkeit und Geschwindigkeit
Ein Build-Job auf Production ist kein Deployment – er ist ein unkontrolliertes Experiment auf dem Live-System. Artefakte aus isolierten CI-Jobs bringen Reproduzierbarkeit, Geschwindigkeit und Sicherheit gleichzeitig.
Inhaltsverzeichnis
- 1. Das Problem: Build auf Production als verstecktes Risiko
- 2. Was ein Build-Artefakt wirklich bedeutet
- 3. Reproduzierbarkeit: Derselbe Build, jederzeit
- 4. Geschwindigkeit: Warum Artefakte schneller sind
- 5. Aufbau eines Magento-Artefakts in GitLab
- 6. Composer-Cache und Artefakt-Größe kontrollieren
- 7. Deploy-Job ohne Build-Tools auf dem Server
- 8. Typische Fehler beim Artefakt-Ansatz
- 9. Build auf Production vs. Artefakt-Ansatz im Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Das Problem: Build auf Production als verstecktes Risiko
Wer composer install auf dem Produktionsserver ausführt, vermischt zwei grundlegend verschiedene Aufgaben: den Build-Prozess und das Deployment. Der Build erzeugt Abhängigkeiten, kompiliert Code und generiert Assets. Das Deployment überträgt einen definierten Zustand auf den Server. Wenn beides zusammenfällt, entsteht ein gefährlicher Graubereich: Der Serverzustand während des Builds ist weder vollständig alt noch vollständig neu. Laufende PHP-FPM-Prozesse greifen auf Dateien zu, die gerade durch Composer überschrieben werden.
Das Risiko ist nicht nur theoretisch. Ein composer install auf Production dauert abhängig vom Netzwerk und dem Server typischerweise zwischen 30 Sekunden und mehreren Minuten. In dieser Zeit können Requests auf halbfertige vendor/-Verzeichnisse treffen. Magento reagiert darauf mit fatalen Fehlern, die sich nicht immer sofort zeigen. Ein setup:di:compile auf Production ist noch riskanter: Er regeneriert den gesamten generierten Code, während die Anwendung antwortet. Das Ergebnis sind 500er, Race Conditions und schwer debugbare Zustandsfehler.
Der Kern des Problems liegt in der fehlenden Trennung von Build-Umgebung und Produktionsumgebung. Production sollte niemals Composer, npm oder Node installiert haben müssen. Wenn diese Tools auf Production vorhanden sind, ist das ein Zeichen dafür, dass der Build-Prozess nicht sauber isoliert ist. Die Lösung ist konsequente Artefakt-Orientierung im GitLab-Workflow.
2. Was ein Build-Artefakt wirklich bedeutet
Ein Build-Artefakt ist das vollständige, unveränderliche Ergebnis eines Build-Prozesses. Es enthält alles, was für den Betrieb der Anwendung benötigt wird: vendor/, generated/, pub/static/ und app/etc/config.php. Es enthält explizit nicht, was umgebungsspezifisch ist: app/etc/env.php, Datenbankverbindungen, API-Keys. Diese Trennung ist der Kern des Artefakt-Ansatzes.
Ein Artefakt ist genau dann korrekt gebaut, wenn es ohne Zugriff auf den Zielserver und ohne Kenntnis der Produktionskonfiguration erstellt werden kann. Das bedeutet: Der Build-Job in GitLab CI läuft in einem Docker-Container mit definierten PHP- und Node-Versionen, installiert Abhängigkeiten aus gesperrten Versionen (composer.lock, package-lock.json) und kompiliert alle generierten Dateien. Das fertige Artefakt wird als GitLab-Artefakt gespeichert und von nachfolgenden Jobs – Test und Deploy – konsumiert.
3. Reproduzierbarkeit: Derselbe Build, jederzeit
Reproduzierbarkeit bedeutet, dass derselbe Commit heute und in sechs Monaten dasselbe Artefakt erzeugt. Das setzt voraus, dass der Build-Job deterministisch ist: festgelegte PHP-Version, festgelegte Composer-Version, composer.lock committet, package-lock.json committet. Wenn der Build auf einem nicht versionierten Server läuft, wo PHP-Patches eingespielt werden und Composer-Versionen stillschweigend wechseln, ist Reproduzierbarkeit nicht erreichbar.
In der Praxis zeigt sich Reproduzierbarkeit im Debugging. Wenn ein Production-Problem auf einen bestimmten Release zurückgeführt werden soll, muss das genaue Artefakt dieses Releases verfügbar oder reproduzierbar sein. Mit einem sauber isolierten Build-Job kann das Artefakt jederzeit aus dem Commit neu erzeugt werden. Mit einem Build auf Production ist das Artefakt das Ergebnis des Serverzustands zum Zeitpunkt des Builds – und dieser Zustand ist nicht versioniert und nicht reproduzierbar.
# Reproducible Magento build job — pinned tools, locked dependencies
build:magento:
stage: build
# Pinned Docker image ensures same PHP version across all builds
image: php:8.4-cli-alpine
variables:
COMPOSER_VERSION: "2.7"
before_script:
- apk add --no-cache git unzip nodejs npm bash
# Install pinned Composer version for reproducibility
- curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/local/bin \
--filename=composer \
--version=$COMPOSER_VERSION
- composer --version
script:
# composer.lock must be committed — ensures same dependency versions
- composer install --no-dev --prefer-dist --no-interaction \
--optimize-autoloader --no-scripts
- composer run-script post-install-cmd --no-interaction
# package-lock.json must be committed — ensures same npm versions
- npm ci --prefix app/design/frontend/Mironsoft/default/web/tailwind
- npm run build --prefix app/design/frontend/Mironsoft/default/web/tailwind
# Generate DI and static content in CI, not on production
- php bin/magento setup:di:compile
- php bin/magento setup:static-content:deploy de_DE -f --jobs=4
artifacts:
name: "magento-$CI_COMMIT_SHORT_SHA"
paths:
- vendor/
- generated/
- pub/static/
- app/etc/config.php
exclude:
- vendor/**/.git
- vendor/**/test/**
- vendor/**/tests/**
expire_in: 3 days
4. Geschwindigkeit: Warum Artefakte schneller sind
Ein häufiges Missverständnis: Der Build auf Production sei schneller, weil der Server schon vorhanden sei. Das Gegenteil ist wahr. Ein Build auf Production konkurriert mit laufenden PHP-Prozessen um CPU und I/O. Composer-Downloads hängen von der Netzwerkverbindung des Servers ab. Der DI-Compile-Schritt blockiert für Minuten die Generierung von Code, der für laufende Requests benötigt wird.
Ein GitLab-Build-Job läuft parallel zu anderen Pipeline-Jobs, nutzt dedizierte CI-Ressourcen und profitiert vom Composer-Cache zwischen Runs. Wenn sich composer.lock nicht geändert hat, lädt der Build-Job keine einzige Abhängigkeit herunter – sie sind alle gecacht. Das Artefakt wird einmal gebaut und kann auf beliebig viele Server deployt werden, ohne den Build-Prozess zu wiederholen. Bei Multi-Server-Setups ist dieser Unterschied besonders deutlich: Ein Build auf drei Production-Servern kostet dreimal die Build-Zeit, ein Artefakt wird einmal gebaut und dreimal deployt.
5. Aufbau eines Magento-Artefakts in GitLab
Das Magento-Artefakt besteht aus vier Kernkomponenten. vendor/ enthält alle PHP-Abhängigkeiten nach dem composer install. generated/ enthält den Dependency-Injection-generierten Code aus dem setup:di:compile. pub/static/ enthält die deployte statische Assets aller aktiven Themes. app/etc/config.php enthält die Modul-Aktivierungsliste, die von setup:upgrade generiert und committed werden sollte.
Was nicht ins Artefakt gehört: app/etc/env.php mit Datenbankverbindungen und Secrets, pub/media/ mit hochgeladenen Medien, var/ mit Logs und Sessions. Diese Dateien leben im shared/-Verzeichnis auf dem Server und werden per Symlink in jeden Release eingebunden. Die scharfe Trennung zwischen dem, was im Artefakt ist, und dem, was auf dem Server liegt, ist die Voraussetzung für einen sicheren Symlink-Switch und für reproduzierbare Deployments.
6. Composer-Cache und Artefakt-Größe kontrollieren
Ohne Cache-Konfiguration lädt jeder Build-Job alle Composer-Pakete erneut herunter. Das kostet Zeit und Bandbreite. GitLab-Pipeline-Caches lösen dieses Problem: Der .cache/composer/-Ordner wird zwischen Builds zwischengespeichert, sodass sich ändernde Pakete nur einmal heruntergeladen werden. Der Cache-Key sollte an $CI_COMMIT_REF_SLUG oder den Hash von composer.lock gebunden sein, damit Cache-Inkompatibilitäten nach Dependency-Updates vermieden werden.
Die Artefakt-Größe ist ein weiterer Kontrollpunkt. Ein unkomprimiertes vendor/-Verzeichnis kann bei großen Magento-Installationen 500 MB oder mehr umfassen. Die exclude-Direktive in der Artefakt-Konfiguration entfernt Test-Verzeichnisse und .git-Unterordner aus Paketen, was die Größe typischerweise um 20–30 % reduziert. Die expire_in-Einstellung steuert, wie lange das Artefakt in GitLab gespeichert bleibt – drei Tage sind für die meisten Workflows ausreichend.
# Composer and npm cache configuration for faster builds
variables:
COMPOSER_CACHE_DIR: "$CI_PROJECT_DIR/.cache/composer"
NPM_CONFIG_CACHE: "$CI_PROJECT_DIR/.cache/npm"
cache:
# Separate cache per branch to avoid cross-branch conflicts
key:
files:
- composer.lock
- app/design/frontend/Mironsoft/default/web/tailwind/package-lock.json
paths:
- .cache/composer/
- .cache/npm/
policy: pull-push
# Artifact size reduction: exclude test directories and git metadata
build:magento:
artifacts:
paths:
- vendor/
- generated/
- pub/static/
- app/etc/config.php
exclude:
# Remove vendor test suites — not needed in production
- "vendor/**/Test/**"
- "vendor/**/Tests/**"
- "vendor/**/.git/**"
- "vendor/**/docs/**"
expire_in: 3 days
when: on_success
7. Deploy-Job ohne Build-Tools auf dem Server
Das Ziel ist ein Produktionsserver, auf dem kein Composer, kein npm und kein Node installiert ist. Der Deploy-Job benötigt nur SSH-Zugang, rsync für die Dateiübertragung und die Magento-CLI (bin/magento) für Deploy-spezifische Schritte wie cache:flush. Der Build-Job hat alles vorbereitet; der Deploy-Job überträgt nur und verlinkt.
Dieser Ansatz hat einen wichtigen Sicherheitsvorteil: Ein Server ohne Build-Tools ist schwerer angreifbar als ein Server mit installierten Entwicklertools. Ein Angreifer, der Zugang zu einem Server mit Composer erlangt, kann deutlich mehr Schaden anrichten als auf einem Server, der nur PHP-FPM und Nginx betreibt. Die Trennung von Build und Deploy ist also nicht nur eine Frage der Reproduzierbarkeit, sondern auch eine Sicherheitsmaßnahme.
8. Typische Fehler beim Artefakt-Ansatz
Der häufigste Fehler beim Umstieg auf den Artefakt-Ansatz ist das Vergessen von app/etc/config.php im Artefakt. Diese Datei wird von setup:upgrade generiert und enthält die Liste der aktivierten Module. Ohne sie kann Magento nach dem Deploy nicht starten. Ein zweiter typischer Fehler: app/etc/env.php landet versehentlich im Artefakt und wird auf alle Umgebungen deployt – inklusive Production-Datenbankverbindungen, die auf Staging nichts zu suchen haben.
Ein dritter Fehler betrifft die expire_in-Einstellung. Wenn das Artefakt abläuft, bevor der Deploy-Job es konsumiert, schlägt der Deploy mit einem kryptischen "artifact not found"-Fehler fehl. Die Ablaufzeit muss so gewählt sein, dass auch bei manuellen Freigaben und Wartezeiten das Artefakt noch verfügbar ist. Für Workflows mit manueller Production-Freigabe sind drei bis fünf Tage ein realistischer Wert.
9. Build auf Production vs. Artefakt-Ansatz im Vergleich
Der Vergleich zwischen Build auf Production und dem Artefakt-Ansatz zeigt, dass es keine Grauzone gibt. Build auf Production ist in professionellen Magento-Deployments kein akzeptabler Kompromiss, sondern ein Anti-Pattern, das durch den Artefakt-Ansatz vollständig ersetzt werden kann.
| Kriterium | Build auf Production | Artefakt-Ansatz (GitLab CI) | Vorteil |
|---|---|---|---|
| Downtime-Risiko | Hoch (Race Conditions) | Minimal (atomarer Switch) | Stabile Antwortzeiten während Deploy |
| Reproduzierbarkeit | Serverzustandsabhängig | Vollständig deterministisch | Gleicher Commit = gleicher Build |
| Build-Dauer | Variabel, belastet Server | Gecacht, isoliert | Kein Einfluss auf Production-Last |
| Server-Anforderungen | Composer, npm, Node nötig | Nur PHP-FPM + Nginx | Kleinere Angriffsfläche |
| Multi-Server-Deploy | Build × Anzahl Server | Build einmal, N-mal deployt | Linear skalierbar |
Die wichtigste Erkenntnis aus dem Vergleich: Der Artefakt-Ansatz ist nicht komplexer als Build auf Production – er ist sauberer. Die initiale Einrichtung des Build-Jobs und der Artefakt-Konfiguration kostet einige Stunden. Im laufenden Betrieb spart sie Stunden pro Deploy und verhindert Vorfälle, die bei Build auf Production regelmäßig auftreten.
10. Zusammenfassung
Der Kern der Argumentation gegen Build auf Production ist klar: Es vermischt zwei getrennte Prozesse, erzeugt Race Conditions, ist nicht reproduzierbar und erfordert Build-Tools auf dem Produktionsserver. Der Artefakt-Ansatz mit GitLab CI trennt Build und Deploy sauber: Der Build läuft einmal in einem isolierten Container mit definierten Versionen, das Artefakt wird in GitLab gespeichert, und der Deploy-Job überträgt das Artefakt atomar auf den Server.
Für Magento ist diese Trennung besonders wichtig, weil der DI-Compile-Schritt und die Static-Content-Generierung zeitaufwändig sind und auf Production unkontrollierte Seiteneffekte haben. Ein sauber aufgebautes GitLab-Artefakt enthält alle generierten Dateien und braucht auf Production nur noch deployt und per Symlink aktiviert zu werden. Das ist der Unterschied zwischen einem Deployment-Prozess, der zufällig funktioniert, und einem, der reproduzierbar zuverlässig ist.
Build-Artefakte für Magento — Das Wichtigste auf einen Blick
Artefakt-Inhalt
vendor/, generated/, pub/static/, app/etc/config.php – nicht env.php, nicht pub/media/, nicht var/.
Reproduzierbarkeit
Gepinntes Docker-Image, composer.lock und package-lock.json committet, deterministischer Build ohne Servereinfluss.
Geschwindigkeit
Composer-Cache zwischen Builds, DI-Compile einmalig im CI, kein Build-Overhead auf Production.
Sicherheit
Kein Composer, npm oder Node auf Production – kleinere Angriffsfläche, klare Trennung von Build- und Laufzeitumgebung.