Kapitel 6
Deployment
Wie Code auf den Server kommt — und wie man merkt, dass er dort auch funktioniert. Der reguläre Weg ist ein Skript, das nach dem Neustart tatsächlich nachfragt, ob der Dienst wieder antwortet.
Zwei Wege
Es gibt zwei Wege, produktiv zu deployen, und einen dritten Workflow, der nur prüft.
| Weg | Auslöser | Umfang |
|---|---|---|
| ./deploy.sh <service> | Manuell auf dem Server | Git-Check, Build, Push, Neustart, Healthcheck, Smoke-Test |
| GitHub Actions (workflow_dispatch) | Manuell in der GitHub-Oberfläche | Build, Push, Deploy per SSH — ohne Healthcheck und Smoke-Test |
| CI (ci.yml) | Automatisch bei Push und Pull Request | Lint, Unit-Tests, Typecheck — deployt nichts |
deploy.sh ist vorzuziehen, weil es nach dem Neustart tatsächlich prüft, ob
der Dienst antwortet. Die Actions-Workflows sind der Fallback, wenn gerade kein
Server-Zugang besteht.
- 1 Git-Check
Arbeitsverzeichnis sauber?
Abbruch bei: Uncommittete Änderungen
- 2 Build
docker build --no-cache
Abbruch bei: Fehlender Patch, fehlende Datei
- 3 Push
registry.raspb.eu
Abbruch bei: Registry nicht erreichbar
- 4 Neustart
dc-all up -d
Abbruch bei: Container startet nicht
- 5 Healthcheck
warten auf „healthy“
Abbruch bei: Timeout nach 30 s bzw. 60 s
- 6 Smoke-Test
curl auf echten Endpunkt
Abbruch bei: Antwort ist nicht 200
Voraussetzungen
- Docker mit Zugriff auf
registry.raspb.eu - Die Compose-Dateien unter
/root/compose - Eine
.envmit den Produktivwerten — Vorlage ist.env.exampleim Repo-Root - Ein sauberes Arbeitsverzeichnis;
deploy.shbricht sonst ab
Cockpit deployen
cd /root/repos/wein-onlineshop/cockpit
npm run check && npm run test # muss grün sein
npm run build # erzeugt build/ via adapter-node
cd /root/repos/wein-onlineshop
./deploy.sh cockpitDer Build-Kontext des Dockerfiles ist bewusst das Repo-Root, weil das
Cockpit packages/ einbindet. Ein Build aus dem Verzeichnis cockpit/ heraus schlägt fehl — das ist kein Fehler in der Konfiguration,
sondern die Folge des Monorepos.
Medusa deployen
Anderes Repository, anderer Paketmanager: Medusa liegt außerhalb des Monorepos und benutzt Yarn 4.
cd /root/workspace/projects/my-medusa-store
yarn install # NIEMALS npm
docker build -f Dockerfile . # ca. 8 Minuten
cd /root/repos/wein-onlineshop
./deploy.sh medusaZwei absichtliche Abbrüche im Build
Der Docker-Build enthält zwei Prüfungen, die ihn abbrechen lassen. Beide sind kein Bug, sondern eine Absicherung:
- Stripe-Connect-Patch.
@medusajs/payment-stripeist exakt auf2.13.1gepinnt. Der Build prüft die Version jeder gehoisteten Kopie, spielt den Patch überall ein und verifiziert danach, dass die zur Laufzeit geladene Kopieon_behalf_ofenthält. Ohne diesen Patch findet Stripe Elements den Payment Intent im Connected Account nicht. - Gutschein-Modul. Der Build prüft, dass alle neun kompilierten Dateien — Modul, Service, Admin- und Store-Routen, Subscriber, PDF-Erzeugung und E-Mail-Vorlage — im Image liegen.
Storefront deployen
cd /root/repos/wein-onlineshop/storefronts/<slug>
npm run check && npm run test
npm run build
cd /root/repos/wein-onlineshop
./deploy.sh storefront-<slug>| Dienst | Dockerfile | Image | Healthcheck | Smoke-Test |
|---|---|---|---|---|
| Cockpit | cockpit/Dockerfile | weinshop-cockpit | 30 s | cockpit.raspb.eu/login |
| Medusa | eigenes Repository | medusa | 60 s | medusa.raspb.eu/health |
| Storefront | storefronts/<slug>/Dockerfile | weinshop-storefront-<slug> | 30 s | shop-<slug>.raspb.eu/katalog |
Datenbank-Migrationen
cd /root/workspace/projects/my-medusa-store
npx medusa db:migrateWann: Nach jeder Änderung an einer Modell-Datei unter medusa/src/modules/*/models/ — also bei neuen Feldern, neuen Entitäten oder
geänderten Relationen.
Smoke-Tests
deploy.sh führt sie automatisch aus. Von Hand geht es so:
curl -s -o /dev/null -w "Cockpit: %{http_code}\n" https://cockpit.raspb.eu/login
curl -s -o /dev/null -w "Medusa: %{http_code}\n" https://medusa.raspb.eu/health
curl -s -o /dev/null -w "Zimmermann: %{http_code}\n" https://shop-zimmermann.raspb.eu/katalogErwartet wird überall 200. Zwei Sonderfälle sind zu kennen:
- 401 ist bei geschützten Admin-Endpunkten in Ordnung. Es belegt, dass Medusa läuft und die Authentifizierung greift.
- 502 oder 000 heißt: Container nicht erreichbar. Dann
docker logsprüfen.
Registry
Alle Images liegen in der privaten Registry:
registry.raspb.eu/weinshop-cockpit:latestregistry.raspb.eu/weinshop-storefront-<slug>:latestregistry.raspb.eu/medusa:latest
Die GitHub-Actions-Workflows melden sich mit den Secrets REGISTRY_USER und REGISTRY_PASS an; der Deploy per SSH nutzt SERVER_HOST und SSH_PRIVATE_KEY.
Fehlerbilder
Diese Tabelle beantwortet die meisten Fragen, die beim Deployen aufkommen. Sie ist aus tatsächlich aufgetretenen Fällen entstanden, nicht aus Vermutungen.
| Symptom | Ursache | Abhilfe |
|---|---|---|
| „Es gibt uncommittete Änderungen!“ | deploy.sh prüft den Git-Status | Committen oder stashen, dann erneut starten |
| Build bricht mit „Patch-Basis ist 2.13.1“ ab | @medusajs/payment-stripe wurde angehoben | Auf 2.13.1 zurückpinnen (ohne Caret) oder den Patch neu erstellen |
| Build bricht mit „FEHLT im Build: …“ ab | Eine Gutschein-Datei fehlt im Kompilat | Prüfen, ob die Quelldatei existiert und der Build sie erfasst |
| Stripe-Zahlungsbox bleibt leer | Connect-Patch nicht im laufenden Image | Neu bauen — nicht per docker cp nachbessern, das überlebt keinen Neustart |
| Änderung ist nach Neustart weg | Per docker cp eingespielt statt gebaut | Sauberen Docker-Build fahren |
| Rechnungs-PDF hängt oder läuft in einen Timeout | Die Vorlage wartet auf externe Bilder | Auf domcontentloaded warten statt auf load |
| Healthcheck-Timeout | Container startet nicht durch | docker logs prüfen; bei Medusa meist eine fehlende Migration |
| Storefront zeigt keine Produkte | Falscher Sales Channel oder Publishable Key | Compose-Datei des Mandanten prüfen |
| Unit-Tests schlagen unerklärlich fehl | Abweichende Paketversion durch npm-Hoisting | Version im betroffenen Paket direkt prüfen |