ein Container Stack pro Pull Request
Eine ephemere Review App entsteht automatisch, sobald ein Pull Request geöffnet wird, und verschwindet spurlos, sobald er gemerged oder geschlossen wird. Docker Compose baut dafür pro Branch einen eigenen, isolierten Stack, erreichbar über eine dynamische Subdomain, ganz ohne manuelles Umgebungs-Management.
Inhaltsverzeichnis
- 1. Was eine ephemere Review App leistet
- 2. Ein Compose-Setup pro Pull Request generieren
- 3. Dynamisches Routing: eine Subdomain pro Branch
- 4. Datenbanken isolieren, ohne für jeden PR Fixtures neu zu bauen
- 5. Aufbau und Abriss in der CI-Pipeline automatisieren
- 6. Labels und Metadaten für zuverlässiges Cleanup
- 7. Ressourcenverbrauch und Limits bei vielen parallelen PRs
- 8. Typische Fehler bei ephemeren Review Apps
- 9. Review Apps im Vergleich zu geteilten Staging-Umgebungen
- 10. Zusammenfassung
- 11. FAQ
1. Was eine ephemere Review App leistet
Eine ephemere Review App ist eine vollständige, isolierte Instanz der Anwendung, die automatisch für einen einzelnen Pull Request entsteht und ebenso automatisch wieder verschwindet, sobald dieser Pull Request nicht mehr relevant ist. Der Kerngedanke: Statt sich eine geteilte Staging-Umgebung zu teilen, in der sich Änderungen verschiedener Branches gegenseitig überschreiben, bekommt jeder Pull Request seinen eigenen, vollständig unabhängigen Container-Stack mit eigener Datenbank, eigenem Cache und eigener erreichbarer URL.
Der Nutzen einer ephemeren Review App zeigt sich vor allem im Review-Prozess selbst. Ein Reviewer muss den Code nicht mehr nur lesen, sondern kann die tatsächliche Änderung in einer laufenden Umgebung anklicken, testen und mit Produktdesignern oder Product Ownern teilen, ohne selbst etwas lokal auszuchecken. Gerade bei visuellen Änderungen an einem Shop-Frontend oder bei komplexen Formular-Workflows ersetzt eine kurze Testrunde in einer echten Umgebung stundenlanges Code-Lesen.
Technisch basiert eine ephemere Review App in den meisten Setups auf Docker Compose, das den kompletten Anwendungsstack, Webserver, Anwendung, Datenbank und gegebenenfalls Cache, in einem eigenen Compose-Projekt pro Branch startet. Die CI-Pipeline übernimmt dabei die komplette Lebenszyklus-Verwaltung: Aufbau bei jedem Push auf den Pull-Request-Branch, Aktualisierung bei weiteren Commits, und vollständiger Abriss beim Merge oder Schließen.
2. Ein Compose-Setup pro Pull Request generieren
Damit mehrere ephemere Review Apps gleichzeitig auf demselben CI-Runner oder Host laufen können, muss jedes Compose-Projekt eindeutig benannt und isoliert sein. Docker Compose unterstützt das über den -p-Parameter (Projektname), der als Präfix für Container-, Netzwerk- und Volume-Namen dient. Wird der Projektname aus der Pull-Request-Nummer abgeleitet, etwa review-pr-482, kollidieren mehrere parallel laufende Review Apps nie miteinander.
Ports dürfen bei mehreren gleichzeitig laufenden ephemeren Review Apps auf demselben Host niemals fest im Compose-File stehen. Stattdessen bindet man Container entweder an zufällig zugewiesene Host-Ports oder, deutlich sauberer, an ein gemeinsames Netzwerk, in dem ein Reverse Proxy anhand von Hostnamen statt Ports routet. Letzteres skaliert deutlich besser, wenn mehr als eine Handvoll Pull Requests gleichzeitig offen sind.
# docker-compose.review.yml -- template rendered per pull request
services:
app:
image: registry.example.com/myapp:${CI_COMMIT_SHA}
environment:
APP_ENV: review
DATABASE_URL: mysql://app:app@db:3306/app
networks: [review-network]
labels:
- "traefik.enable=true"
- "traefik.http.routers.pr-${PR_NUMBER}.rule=Host(`pr-${PR_NUMBER}.review.example.com`)"
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: app
networks: [review-network]
tmpfs:
- /var/lib/mysql # ephemeral storage -- no cleanup of data files needed
networks:
review-network:
name: review-pr-${PR_NUMBER}
3. Dynamisches Routing: eine Subdomain pro Branch
Reviewer sollen eine ephemere Review App mit einem einzigen Klick erreichen können, ohne Ports oder IP-Adressen zu kennen. Ein Reverse Proxy wie Traefik löst das elegant über Labels: Jeder App-Container bekommt beim Start ein Traefik-Label mit einer Routing-Regel, die auf einer eindeutigen Subdomain basiert, üblicherweise abgeleitet aus der Pull-Request-Nummer, etwa pr-482.review.example.com. Traefik erkennt neue Container automatisch über die Docker-Provider-Integration und aktualisiert sein Routing ohne Neustart.
Für ephemere Review Apps mit HTTPS empfiehlt sich ein Wildcard-Zertifikat für die Review-Domain, etwa *.review.example.com, statt für jeden Pull Request ein eigenes Zertifikat auszustellen. Traefik kann Wildcard-Zertifikate über den DNS-01-Challenge-Modus von Let's Encrypt automatisch verwalten, was den gesamten Zertifikatsprozess von der Pull-Request-Lebensdauer entkoppelt.
4. Datenbanken isolieren, ohne für jeden PR Fixtures neu zu bauen
Eine eigene, isolierte Datenbank pro ephemerer Review App ist Pflicht, damit Testdaten unterschiedlicher Pull Requests sich niemals vermischen. Der naheliegende Ansatz, für jeden Pull Request einen komplett leeren Datenbank-Container zu starten und dann ein vollständiges Produktions-Backup einzuspielen, ist bei größeren Datenmengen aber zu langsam, um in wenigen Minuten eine nutzbare Review App bereitzustellen.
Schneller funktioniert das Vorladen eines kompakten, anonymisierten Seed-Datensatzes in ein Docker Volume oder Image, das dann als Ausgangspunkt für jede neue ephemere Review App dient. Ein solches Seed-Image wird einmalig aus einem repräsentativen Datenauszug gebaut und in der Registry versioniert, sodass der eigentliche Start jeder Review App nur noch das Kopieren eines fertigen Datenbank-Volumes erfordert, statt Migrationen und Fixtures live auszuführen.
#!/usr/bin/env bash
# seed-review-db.sh -- fast database seeding for ephemeral review apps
set -euo pipefail
PR_NUMBER="${1:?Usage: seed-review-db.sh <pr-number>}"
VOLUME_NAME="review-pr-${PR_NUMBER}-db"
echo "[seed] Creating isolated volume for PR #${PR_NUMBER}"
docker volume create "${VOLUME_NAME}"
# Copy a pre-built, anonymized seed dataset into the fresh volume
docker run --rm \
-v "${VOLUME_NAME}:/var/lib/mysql" \
-v review-seed-data:/seed:ro \
alpine sh -c "cp -a /seed/. /var/lib/mysql/"
echo "[seed] Volume ${VOLUME_NAME} ready in seconds, not minutes"
5. Aufbau und Abriss in der CI-Pipeline automatisieren
Der komplette Lebenszyklus einer ephemeren Review App muss über CI-Pipeline-Trigger gesteuert werden, nicht über manuelle Eingriffe. GitLab CI bietet dafür das native environment-Konzept mit on_stop-Jobs, die automatisch ausgeführt werden, sobald ein Merge Request geschlossen oder gemerged wird. GitHub Actions erreicht dasselbe über einen Workflow, der auf das closed-Event eines Pull Requests reagiert.
Wichtig bei der Automatisierung von ephemeren Review Apps ist, dass der Stop-Job zuverlässig läuft, selbst wenn der zugehörige Deploy-Job zuvor fehlgeschlagen ist. Ein Review-App-Stack, der halb aufgebaut wurde und dann nie wieder abgerissen wird, weil der Cleanup-Job an eine erfolgreiche vorherige Pipeline gekoppelt war, sammelt sich über Wochen zu erheblichem Ressourcen-Müll an.
# .gitlab-ci.yml -- ephemeral review app with automatic teardown
deploy-review:
stage: deploy
environment:
name: review/$CI_COMMIT_REF_SLUG
url: https://pr-$CI_MERGE_REQUEST_IID.review.example.com
on_stop: stop-review
script:
- export PR_NUMBER=$CI_MERGE_REQUEST_IID
- envsubst < docker-compose.review.yml > compose.rendered.yml
- docker compose -p review-pr-$PR_NUMBER -f compose.rendered.yml up -d
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
stop-review:
stage: deploy
environment:
name: review/$CI_COMMIT_REF_SLUG
action: stop
script:
- docker compose -p review-pr-$CI_MERGE_REQUEST_IID down -v
when: manual
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
6. Labels und Metadaten für zuverlässiges Cleanup
Selbst mit einem gut konfigurierten on_stop-Job bleiben gelegentlich verwaiste Ressourcen zurück, etwa wenn ein Runner während des Cleanups abstürzt. Für ephemere Review Apps empfiehlt sich deshalb ein zusätzlicher, zeitgesteuerter Aufräum-Job, der alle Container und Volumes mit einem bestimmten Label identifiziert und nach Ablauf einer maximalen Lebensdauer automatisch entfernt, unabhängig vom Pipeline-Status des ursprünglichen Pull Requests.
Ein konsistentes Label-Schema ist dafür Voraussetzung: Jeder Container einer ephemeren Review App bekommt beim Start ein Label wie review-app=true zusammen mit der Pull-Request-Nummer und dem Erstellungszeitpunkt. Ein täglich laufender Cron-Job filtert dann per docker ps --filter "label=review-app=true" alle betroffenen Ressourcen und entfernt jene, deren Erstellungszeitpunkt eine definierte Frist, etwa 14 Tage, überschreitet.
7. Ressourcenverbrauch und Limits bei vielen parallelen PRs
Je aktiver ein Team arbeitet, desto mehr ephemere Review Apps laufen gleichzeitig, und jede davon belegt CPU, Arbeitsspeicher und Speicherplatz auf dem Review-Host. Ohne Limits kann ein einzelner ressourcenhungriger Pull Request alle anderen Review Apps auf demselben Host verlangsamen. Für jeden Service im Compose-File sollten deshalb deploy.resources.limits gesetzt werden, auch wenn Compose diese außerhalb von Swarm nur als Empfehlung an die Docker Engine weitergibt, nicht als harte Kubernetes-artige Garantie.
Zusätzlich empfiehlt sich eine Obergrenze für die Anzahl gleichzeitig laufender ephemerer Review Apps pro Host. Erreicht ein Team diese Grenze, kann die Pipeline ältere, inaktive Review Apps automatisch stoppen, bevor eine neue gestartet wird, statt den Host durch unbegrenztes Wachstum zu überlasten. Diese Grenze lässt sich einfach über einen Zähler-Job realisieren, der vor jedem Deploy die Anzahl laufender Review-App-Netzwerke prüft.
8. Typische Fehler bei ephemeren Review Apps
Der häufigste Fehler beim Aufbau von ephemeren Review Apps ist, produktionsnahe Secrets in die Review-Umgebung zu kopieren, etwa echte Zahlungsdienst-Zugangsdaten oder echte Kunden-E-Mail-Konfiguration. Reviewer testen typischerweise mit unbedachten Eingaben, und eine Review App, die versehentlich echte E-Mails verschickt oder echte Zahlungen anstößt, verursacht handfeste Probleme außerhalb der eigentlichen Testumgebung.
# WRONG: production secrets leaking into a review app
docker compose -p review-pr-482 --env-file .env.production up -d
# RIGHT: dedicated, sandboxed secrets for every review app
docker compose -p review-pr-482 --env-file .env.review-sandbox up -d
# .env.review-sandbox points to test payment gateways, mail catchers, etc.
Ein zweiter verbreiteter Fehler ist, den Cleanup-Job nicht robust gegen Teilausfälle zu gestalten. Wenn ein docker compose down mangels Berechtigungen fehlschlägt oder der Runner während des Vorgangs neu startet, bleibt eine ephemere Review App unbemerkt aktiv. Ein regelmäßiger, unabhängiger Aufräum-Job auf Basis von Labels und Alter fängt genau solche Teilausfälle ab, statt sich allein auf den Erfolg des ursprünglichen Stop-Jobs zu verlassen.
9. Review Apps im Vergleich zu geteilten Staging-Umgebungen
Die folgende Tabelle stellt geteilte Staging-Umgebungen den ephemeren Review Apps pro Pull Request gegenüber.
| Aspekt | Geteiltes Staging | Ephemere Review App | Konsequenz |
|---|---|---|---|
| Isolation zwischen Branches | Keine, Änderungen überschreiben sich | Vollständig, ein Stack pro PR | Kein gegenseitiges Überschreiben mehr |
| Verfügbarkeit für Review | Warteschlange bei vielen PRs | Sofort und parallel verfügbar | Schnelleres Feedback im Review |
| Lebensdauer | Dauerhaft, manuell gepflegt | An PR-Lebenszyklus gekoppelt | Kein manueller Reset nötig |
| Ressourcenverbrauch | Konstant, auch ungenutzt | Nur während PR aktiv ist | Geringere Dauerkosten |
| Setup-Aufwand | Gering, einmalig | Höher, aber einmalig automatisiert | Lohnt sich ab wenigen parallelen PRs |
Der Mehraufwand beim initialen Aufbau von ephemeren Review Apps amortisiert sich, sobald ein Team regelmäßig mit mehreren parallel offenen Pull Requests arbeitet. Die Zeitersparnis durch sofort verfügbare, konfliktfreie Testumgebungen übersteigt den Automatisierungsaufwand meist bereits nach den ersten Wochen produktiven Einsatzes.
Mironsoft
Review Apps, Container-Automatisierung und Deployment-Infrastruktur
Review Apps pro Pull Request einrichten?
Wir bauen ephemere Review-App-Pipelines mit Docker Compose, dynamischem Routing und zuverlässigem Cleanup, damit jeder Pull Request seine eigene, sofort testbare Umgebung bekommt.
Compose-Templates
Pro-PR-Stacks mit isolierten Netzwerken und Volumes aufsetzen
Dynamisches Routing
Traefik-basiertes Subdomain-Routing inklusive Wildcard-TLS einrichten
Cleanup-Automatisierung
Label-basierte Aufräum-Jobs gegen verwaiste Ressourcen implementieren
10. Zusammenfassung
Eine ephemere Review App pro Pull Request löst das grundlegende Problem geteilter Staging-Umgebungen: Änderungen verschiedener Branches überschreiben sich nicht mehr gegenseitig, und jeder Reviewer bekommt eine sofort erreichbare, isolierte Testumgebung. Docker Compose mit projektbasierter Isolation, dynamischem Routing über Traefik und vorgeladenen Seed-Datenbanken macht den Aufbau schnell genug, um pro Pull Request praktikabel zu sein.
Der entscheidende Erfolgsfaktor liegt im zuverlässigen Abriss: Ohne robuste, labelbasierte Cleanup-Automatisierung sammeln sich verwaiste Container und Volumes an, die Ressourcen binden und Kosten verursachen. Wer den kompletten Lebenszyklus, vom Aufbau bei jedem Push bis zum garantierten Abriss beim Schließen des Pull Requests, konsequent in die CI-Pipeline integriert, gewinnt einen der wirkungsvollsten Hebel für schnelleres, konfliktfreies Code-Review.
Ephemere Review Apps — Das Wichtigste auf einen Blick
Ein Stack pro PR
Compose-Projektname aus der PR-Nummer ableiten, damit parallele Review Apps nie kollidieren.
Dynamisches Routing
Traefik-Labels und Wildcard-TLS machen jede Review App über eine eigene Subdomain erreichbar.
Schnelles Seeding
Vorgeladene, anonymisierte Datensätze statt Live-Migrationen pro Review App.
Labelbasiertes Cleanup
Zeitgesteuerter Aufräum-Job als Absicherung gegen fehlgeschlagene on_stop-Jobs.