Deployment-Demo v3

STAGING

Gemeinsames Staging — neu gebaut bei jedem Push auf main

Branch
main
Version/Commit
f12907d7
Adresse
demo-app.staging.minotera.com
Container
9da858ba4feb
Prozessstart
2026-08-11T12:51:03+00:00
Uptime
31 min 29 s

Live-Ticker — Deploy ohne Lücke

Der Ticker fragt zweimal pro Sekunde /health ab und zeigt an, welcher Container antwortet. Jetzt einen Commit pushen und zusehen: die Container-Kennung wechselt, ohne dass ein Punkt rot wird. kamal-proxy schaltet erst um, wenn der neue Container gesund ist. Ohne das hiesse jeder Deploy: ein paar Sekunden Verbindungsfehler.

Ticker startet …

Gästebuch — Zustand überlebt den Deploy

Die Einträge liegen in PostgreSQL, einem eigenen Container neben der App (Kamal-Accessory), dessen Daten auf dem Server-Volume liegen. Jeder Eintrag trägt die Version, die ihn geschrieben hat — alte Einträge aus längst ersetzten Containern sind immer noch da. Das ist der Unterschied zwischen einem Deploy und einem Datenverlust.

DATABASE_URL ist nicht gesetzt — auf diesem Stand läuft keine Datenbank. Auf dem Produktionsserver stellt Kamal sie als Accessory bereit.

Zwei Ablagen — nur eine überlebt

Der Knopf legt dieselbe Notiz zweimal ab: links auf dem eingehängten Volume, rechts im Dateisystem des Containers. Nach dem nächsten Deploy existiert nur noch die linke Liste. Genau dieser Unterschied ist der häufigste Produktions-Unfall — Uploads, die im Container lagen und mit ihm starben. Das Go-live-Audit sucht exakt danach.

Volume (bleibt)

    Container (stirbt)

      Health-Schalter — krank geht nicht live

      Der Schalter legt eine Marke auf dem Datenvolume ab — auch ein frisch deployter Container liest sie und meldet sich krank. Die Folge: der nächste Deploy bleibt stehen, weil kamal-proxy einen Container ohne gesunden Healthcheck nie live schaltet — die alte Version läuft einfach weiter. Diese Seite bleibt dabei erreichbar; krank ist nur der Healthcheck. Reparieren, erneut deployen, alles läuft.

      Langsame Anfrage — niemand wird abgerissen

      Der Knopf startet eine Anfrage, die 20 Sekunden braucht. Währenddessen deployen: der alte Container bekommt SIGTERM, nimmt nichts Neues mehr an — aber diese Anfrage darf fertig werden, erst dann stirbt er (Kamal wartet beim Stoppen 30 s). Ohne sauberes SIGTERM-Handling würde jeder Deploy laufende Anfragen mitten im Satz kappen.

      Start-Historie — jeder Deploy hinterlässt eine Zeile

      Bei jedem Prozessstart trägt sich die App mit Version und Container-Kennung in die Datenbank ein. Die Liste ist die Deploy-Geschichte dieses Stands — und der Beleg, dass all die Container kamen und gingen, während die Daten blieben.

      Braucht die Datenbank (siehe Gästebuch).

      Backup — läuft nachts, meldet sich hier

      Ein Backup, das niemand sieht, ist ein Gerücht. Der Backup-Container sichert die Datenbank jede Nacht und legt seinen letzten Stand als Datei aufs Volume — die Seite zeigt ihn ungefiltert. Wiederherstellung ist eine dokumentierte Übung (restore.sh), keine Improvisation.

      Noch kein Status abgelegt. Auf dem Produktionsserver schreibt der Backup-Begleiter (pg_dump → restic → S3) nach jedem Lauf eine Zusammenfassung auf das Datenvolume — sie erscheint dann hier.