- Deploy-Scripts: Image-Promotion statt Rebuild (docker tag + up -d), deploy.env fuer Server-Konfiguration, -p fuer Projekt-Namen, Health-Check mit Host-Header und /xhr/health-check - docker-compose.prod.yaml: name-Feld entfernt (Projekt-Name per -p) - deploy.env.example als Vorlage hinzugefuegt - .vibe/skills/client-build/SKILL.md aus Git-Index entfernt (gitignore) - Deployment-Anleitung: Zugangsdaten, deploy.env, Image-Promotion, prod ohne eigenes Repo, git-clone-Hinweis, Log-Befehle mit -p - Deploy-lokal-testen.md: neue Anleitung fuer lokales Testen Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
16 KiB
Anleitung: Automatisches Deployment einrichten
Diese Anleitung richtet sich an den Administrator des Deploy-Servers. Sie beschreibt, wie der automatische Deploy-Mechanismus fuer KB-CRM eingerichtet und betrieben wird.
1. Architektur ueberblick
Entwickler
│ git push origin main
▼
┌─────────────────┐
│ Git-Remote │ (z.B. Gitea auf git.everdc.eu)
└────────┬────────┘
│ Webhook oder post-receive Hook
▼
┌─────────────────┐
│ Deploy-Server │
│ (Deploy-Script) │
└────────┬────────┘
│
┌──────────┴──────────┐
▼ ▼
┌─────────────────┐ ┌─────────────────┐
│ Stufe 1: TEST │ │ Stufe 2: PROD │
│ (automatisch) │ │ (manuell) │
└─────────────────┘ └─────────────────┘
Prinzip:
- Jeder
git pushaufmainloest automatisch ein Deployment auf dem Test-Server aus (Stufe 1). - Nach erfolgreicher Verifikation wird manuell auf den Prod-Server deployt (Stufe 2).
- In Prod wird der Python-Code in das App-Image kopiert. Der TypeScript-Quellcode wird waehrend des Docker-Builds in einer Multi-Stage-Build-Stage kompiliert (tsc + rollup); in das finale NGINX-Image wird nur das fertige JS-Bundle uebernommen, nicht der TypeScript-Quellcode. Es wird kein Node.js, npm oder Python-venv auf dem Server benoetigt.
- Der Deploy-Server benoetigt nur:
git,dockerunddocker compose.
2. Voraussetzungen auf dem Deploy-Server
Folgende Software muss installiert sein:
| Software | Version | Zweck |
|---|---|---|
git |
aktuell | Code vom Remote-Repository holen |
docker |
aktuell | Container bauen und starten |
docker compose |
v2+ | Multi-Container-Orchestrierung |
curl |
aktuell | Health-Check nach Deploy |
Docker Compose muss als Plugin installiert sein (Befehl: docker compose,
nicht docker-compose).
Git-Zugangsdaten konfigurieren
Das git clone und git fetch in den Deploy-Scripts nutzen die
Git-Credentials, die auf dem Deploy-Server konfiguriert sind. Die
Zugangsdaten stehen nicht in den Scripts oder Konfigurationsdateien.
Drei Moeglichkeiten:
| Methode | Einrichtung | Wo hinterlegt |
|---|---|---|
| SSH-Key | git clone git@git.everdc.eu:.../kbcrm (SSH-URL verwenden) |
~/.ssh/id_rsa auf dem Deploy-Server |
| Git-Credential-Store | git config --global credential.helper store |
~/.git-credentials auf dem Deploy-Server |
| Deploy-Token (Gitea) | Token in Remote-URL: https://token:secret@git.everdc.eu/... |
In der origin-URL des geklonten Repos |
Empfohlen: SSH-Key oder Deploy-Token. Der Credential-Store speichert Passwoerter im Klartext und sollte nur fuer Test-Umgebungen verwendet werden.
3. Verzeichnisstruktur auf dem Deploy-Server
Es werden zwei Umgebungen (test-prod und prod) parallel betrieben:
/opt/kbcrm/
├── test-prod/
│ ├── repo/ ← git clone des Repos (einziges Repo auf dem Server)
│ └── .env ← test-prod Umgebung (eigene Ports, eigene DB)
├── prod/
│ └── .env ← prod Umgebung (kein eigenes Repo — Images per docker tag)
└── scripts/
├── deploy-kbcrm-test.sh ← aus dem Repo (scripts/)
├── deploy-kbcrm-prod.sh ← aus dem Repo (scripts/)
└── deploy.env ← Server-spezifische Konfiguration (nicht im Repo)
Die SQLite-Datenbanken liegen ausserhalb des Repos in einem bind-mount
(PYTHON_DB_DIR), der beim Deploy nicht beruehrt wird.
4. Einrichtung: Schritt fuer Schritt
4.1. Repositories klonen
sudo mkdir -p /opt/kbcrm/test-prod /opt/kbcrm/prod
# Repository klonen (nur einmal — prod nutzt die Images aus test-prod)
# WICHTIG: git clone wird nur beim ersten Mal ausgefuehrt. Wenn das Verzeichnis
# bereits existiert (z.B. .env wurde bereits abgelegt), schlaegt clone fehl.
# Weitere Updates werden durch das deploy-kbcrm-test.sh Script via
# git fetch + git reset --hard durchgefuehrt — kein manueller clone mehr.
sudo git clone https://git.everdc.eu/chmln-app-dev/kbcrm /opt/kbcrm/test-prod/repo
# Falls das Verzeichnis bereits existiert und aktualisiert werden soll:
# cd /opt/kbcrm/test-prod/repo && git fetch origin main && git reset --hard origin/main
# Oder einfach: /opt/kbcrm/scripts/deploy-kbcrm-test.sh
4.2. .env-Dateien anlegen
Kopieren Sie die Vorlage aus dem Repo und passen Sie die Werte an:
# Test-Prod
cp /opt/kbcrm/test-prod/repo/env-sample /opt/kbcrm/test-prod/.env
# Prod (Vorlage aus test-prod-Repo)
cp /opt/kbcrm/test-prod/repo/env-sample /opt/kbcrm/prod/.env
4.3. .env fuer Test-Prod anpassen
vi /opt/kbcrm/test-prod/.env
Folgende Einstellungen muessen angepasst werden:
# WICHTIG: BUILD_ENVIRONMENT muss in den .env-Dateien auf dem Deploy-Server
# NICHT gesetzt werden. Die Deploy-Scripts rufen docker compose explizit
# mit -f docker-compose.prod.yaml auf und ignorieren COMPOSE_FILE.
# Daher kann BUILD_ENVIRONMENT und COMPOSE_FILE aus der .env geloescht
# oder ignoriert werden.
# NGINX-Server
NGINX_USE_SSL=true
NGINX_HOST_PORT=8443 # eigener Port fuer Test-Prod
NGINX_SERVER_NAME=test.kbp_crm.mylocal.de
# NGINX_STATIC_DIR und NGINX_CONFIG_TEMPLATE_DIR werden in Prod nicht
# benoetigt (statische Dateien und Templates sind im Image).
# WICHTIG: Auch bei NGINX_USE_SSL=false duerfen NGINX_CERTS, NGINX_CERT und
# NGINX_CERT_KEY NICHT geloescht werden. docker-compose.base.yaml bindet
# ${NGINX_CERTS} immer als Volume (/etc/certs) ein — ein fehlender Wert
# fuehrt zu einem Compose-Fehler. Bei SSL=false reicht es, Platzhalterwerte
# zu setzen (z.B. NGINX_CERTS auf ein beliebiges Verzeichnis zeigen lassen).
NGINX_CERTS=/opt/kbcrm/test-prod/certs # Pfad zu SSL-Zertifikaten
NGINX_CERT=test-wildcard.mylocal.crt
NGINX_CERT_KEY=test-wildcard.mylocal.key
# Python App-Server
PYTHON_DB_DIR=/opt/kbcrm/test-prod/data # eigene DB fuer Test-Prod
# OIDC-Settings anpassen (ggf. separater OIDC-Client fuer Test)
ZITADEL_ISSUER=https://id.vmlx.de
ZITADEL_CLIENT_ID=<test-client-id>
ZITADEL_CLIENT_SECRET=<test-client-secret>
ZITADEL_REDIRECT_URI=https://test.kbp_crm.mylocal.de/auth/callback
4.4. .env fuer Prod anpassen
vi /opt/kbcrm/prod/.env
NGINX_HOST_PORT=443 # Produktions-Port
NGINX_SERVER_NAME=kbp_crm.mylocal.de
NGINX_CERTS=/opt/kbcrm/prod/certs
NGINX_CERT=wildcard.mylocal.crt
NGINX_CERT_KEY=wildcard.mylocal.key
# Auch hier gilt: Bei NGINX_USE_SSL=false die Zertifikats-Variablen nicht
# loeschen, sondern Platzhalterwerte stehen lassen (s. Hinweis oben).
PYTHON_DB_DIR=/opt/kbcrm/prod/data # eigene DB fuer Prod
ZITADEL_REDIRECT_URI=https://kbp_crm.mylocal.de/auth/callback
4.5. Datenbank-Verzeichnisse erstellen
sudo mkdir -p /opt/kbcrm/test-prod/data
sudo mkdir -p /opt/kbcrm/prod/data
4.6. SSL-Zertifikate ablegen
Kopieren Sie die Zertifikate in die in .env angegebenen Verzeichnisse:
sudo mkdir -p /opt/kbcrm/test-prod/certs /opt/kbcrm/prod/certs
sudo cp wildcard.mylocal.crt wildcard.mylocal.key /opt/kbcrm/test-prod/certs/
sudo cp wildcard.mylocal.crt wildcard.mylocal.key /opt/kbcrm/prod/certs/
4.7. Deploy-Scripts kopieren
Die Scripts liegen im Repo unter scripts/. Kopieren Sie sie an einen
zentralen Ort:
sudo mkdir -p /opt/kbcrm/scripts
sudo cp /opt/kbcrm/test-prod/repo/scripts/deploy-kbcrm-test.sh /opt/kbcrm/scripts/
sudo cp /opt/kbcrm/test-prod/repo/scripts/deploy-kbcrm-prod.sh /opt/kbcrm/scripts/
sudo chmod +x /opt/kbcrm/scripts/*.sh
4.8. deploy.env anlegen (Server-spezifische Konfiguration)
Die Deploy-Scripts laden ihre Server-spezifische Konfiguration (Pfade, Ports,
Projekt-Namen) aus einer Datei deploy.env, die im gleichen Verzeichnis wie
die Scripts liegen muss. Diese Datei ist nicht Teil des Repos und wird
nicht per git pull ueberschrieben.
Kopieren Sie die Vorlage und passen Sie die Werte an:
cp /opt/kbcrm/test-prod/repo/scripts/deploy.env.example /opt/kbcrm/scripts/deploy.env
vi /opt/kbcrm/scripts/deploy.env
Inhalt der deploy.env:
# --- Test-Prod Umgebung (fuer deploy-kbcrm-test.sh) ---
DEPLOY_REPO_DIR=/opt/kbcrm/test-prod/repo
DEPLOY_ENV_FILE=/opt/kbcrm/test-prod/.env
DEPLOY_PROJECT_NAME=kbptest
DEPLOY_HEALTH_PORT=8443
# --- Prod Umgebung (fuer deploy-kbcrm-prod.sh) ---
DEPLOY_PROD_COMPOSE_FILE=/opt/kbcrm/test-prod/repo/docker-compose.prod.yaml
DEPLOY_PROD_ENV_FILE=/opt/kbcrm/prod/.env
DEPLOY_PROD_PROJECT_NAME=kbpprod
DEPLOY_PROD_TEST_PROJECT_NAME=kbptest
DEPLOY_PROD_HEALTH_PORT=443
Wenn deploy.env fehlt, verwenden die Scripts ihre eingebauten Defaults
(die den obigen Werten entsprechen). Die deploy.env ist nur noetig, wenn
Ihre Verzeichnisstruktur oder Ports abweichen.
5. Git-Hook einrichten (automatisches Test-Deploy)
Variante A: post-receive Hook (direkt auf dem Git-Server)
Wenn Shell-Zugang zum Git-Server besteht:
# Auf dem Git-Server, im bare Repository:
vi /srv/git/kbcrm.git/hooks/post-receive
#!/bin/bash
while read oldrev newrev ref; do
if [ "$ref" = "refs/heads/main" ]; then
ssh deploy-user@deploy-server "/opt/kbcrm/scripts/deploy-kbcrm-test.sh"
fi
done
chmod +x /srv/git/kbcrm.git/hooks/post-receive
Variante B: Webhook (empfohlen fuer Gitea)
- In Gitea: Repository-Einstellungen -> Webhooks -> Webhook hinzufuegen
- URL:
http://deploy-server:9000/webhook(Beispiel) - Content-Type:
application/json - Trigger: "Push Events" (nur auf
main) - Auf dem Deploy-Server: kleiner HTTP-Listener, der den Webhook entgegennimmt und das Deploy-Script startet.
Beispiel fuer einen einfachen Webhook-Listener (systemd-Service mit Python):
# /opt/kbcrm/scripts/webhook-listener.py
from http.server import HTTPServer, BaseHTTPRequestHandler
import subprocess
class Handler(BaseHTTPRequestHandler):
def do_POST(self):
subprocess.run(["/opt/kbcrm/scripts/deploy-kbcrm-test.sh"])
self.send_response(200)
self.end_headers()
HTTPServer(("", 9000), Handler).serve_forever()
Systemd-Service:
# /etc/systemd/system/kbcrm-webhook.service
[Unit]
Description=KB-CRM Deploy Webhook Listener
After=network.target
[Service]
ExecStart=/usr/bin/python3 /opt/kbcrm/scripts/webhook-listener.py
Restart=always
User=deploy-user
[Install]
WantedBy=multi-user.target
sudo systemctl enable --now kbcrm-webhook
6. Deployment durchfuehren
6.1. Automatisches Deploy nach Test-Prod
Wird durch git push ausgeloest (sofern Hook eingerichtet). Manuell:
/opt/kbcrm/scripts/deploy-kbcrm-test.sh
Das Script fuehrt folgende Schritte aus:
git pull(latest main)docker compose up -d --build(baut beide Images: NGINX mit TypeScript- Build und Python mit Anwendungscode)- Health-Check
6.2. Manuelle Promotion nach Prod (Image-Promotion)
Nach Verifikation auf dem Test-Server:
/opt/kbcrm/scripts/deploy-kbcrm-prod.sh
Das Script fragt eine Bestaetigung ("yes/no") und uebernimmt dann die
getesteten Images aus test-prod per docker tag — kein Rebuild, kein git pull.
Prod startet mit exakt dem Stand, der in test-prod verifiziert wurde. Nur
die .env unterscheidet sich (Ports, Zertifikate, DB-Pfad, OIDC).
Ablauf:
- Sicherheitsabfrage ("yes/no")
docker tag— Images vonkbptest-*nachkbpprod-*kopierendocker compose up -d— Container starten (ohne--build)- Health-Check
Wichtig: Das Prod-Script fuehrt kein git pull aus. Eine Aenderung an
der docker-compose.prod.yaml zwischen test-prod und Promotion wuerde
bedeuten, dass prod mit einer anderen Konfiguration startet als verifiziert.
Bei Aenderungen an der Compose-Datei muss erst ein neues test-prod-Deploy
durchgefuehrt werden.
6.3. Alternative: Git-Tag-basierte Promotion
Statt das Prod-Script manuell aufzurufen, kann ein Git-Tag das Prod-Deploy ausloesen:
# Auf dem Entwickler-Rechner:
git tag -a v00.00.02 -m "Release: deploy to prod"
git push origin v00.00.02
Der post-receive-Hook prueft auf Tags:
#!/bin/bash
while read oldrev newrev ref; do
if [ "$ref" = "refs/heads/main" ]; then
ssh deploy-user@deploy-server "/opt/kbcrm/scripts/deploy-kbcrm-test.sh"
elif [[ "$ref" = refs/tags/v* ]]; then
ssh deploy-user@deploy-server "/opt/kbcrm/scripts/deploy-kbcrm-prod.sh"
fi
done
7. Wartung und Fehlersuche
Logs anzeigen
# Test-Prod
docker compose -p kbptest --env-file /opt/kbcrm/test-prod/.env \
-f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml logs
# Prod
docker compose -p kbpprod --env-file /opt/kbcrm/prod/.env \
-f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml logs
# Nur Python-Container
docker compose -p kbpprod --env-file /opt/kbcrm/prod/.env \
-f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml logs pythonapp
# Nur NGINX-Container
docker compose -p kbpprod --env-file /opt/kbcrm/prod/.env \
-f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml logs nginx-proxy
Container-Status pruefen
docker compose -p kbpprod --env-file /opt/kbcrm/prod/.env \
-f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml ps
Manuell in den Container wechseln
docker compose -p kbpprod --env-file /opt/kbcrm/prod/.env \
-f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml exec pythonapp bash
Rollback
Bei Problemen kann auf einen frueheren Stand zurueckgekehrt werden:
# Auf dem Deploy-Server:
cd /opt/kbcrm/test-prod/repo
git log --oneline -10 # frueheren Commit finden
git checkout <commit-hash>
docker compose -p kbpprod --env-file /opt/kbcrm/prod/.env \
-f docker-compose.prod.yaml up -d --build
Datenbank sichern
Die SQLite-Datenbanken liegen im bind-mount (PYTHON_DB_DIR).
Sicherung:
cp /opt/kbcrm/prod/data/*.db /backup/kbcrm-prod-$(date +%Y%m%d).db
Docker-Images aufraeumen
Nach mehreren Deploys koennen alte Images Speicher belegen:
docker image prune -f
8. Uebersicht: .env-Variablen fuer Prod
| Variable | Erforderlich | Beschreibung |
|---|---|---|
NGINX_USE_SSL |
ja | SSL aktivieren (true/false) |
NGINX_HOST_PORT |
ja | Externer Port (443 fuer SSL, 8080 fuer no-SSL) |
NGINX_SERVER_NAME |
ja | Server-Name fuer NGINX-Konfiguration |
NGINX_CERTS |
ja | Pfad zu SSL-Zertifikaten (bind-mount). Auch bei SSL=false erforderlich — Compose bindet diesen Pfad immer als Volume ein |
NGINX_CERT |
ja | Zertifikatsdatei. Bei SSL=false nicht verwendet, darf aber nicht geloescht werden (Platzhalter reicht) |
NGINX_CERT_KEY |
ja | Privater Schluessel. Bei SSL=false nicht verwendet, darf aber nicht geloescht werden (Platzhalter reicht) |
NGINX_STATIC_DIR |
nein | Nur in Dev; in Prod im Image |
NGINX_CONFIG_TEMPLATE_DIR |
nein | Nur in Dev; in Prod im Image |
PYTHON_DB_DIR |
ja | Pfad zu SQLite-Datenbanken (bind-mount) |
PYTHON_DEV_DIR |
nein | Nur in Dev |
APP_DEBUG |
nein | Nur in Dev; in Prod nicht setzen |
BUILD_ENVIRONMENT |
nein | Nicht relevant — Deploy-Scripts geben Compose-Datei explizit an. In .env auf Deploy-Server nicht erforderlich |
ZITADEL_* |
ja | OIDC-Konfiguration |
COMPOSE_FILE |
nein | Wird von Deploy-Scripts ignoriert (s. BUILD_ENVIRONMENT) |
9. Checkliste fuer den Admin
- Docker und Docker Compose installiert
- Git installiert, Repository geklont (test-prod + prod)
.env-Dateien erstellt und angepasst (Ports, DB, Zertifikate, OIDC)- Datenbank-Verzeichnisse erstellt (
PYTHON_DB_DIR) - SSL-Zertifikate abgelegt (
NGINX_CERTS) - Deploy-Scripts kopiert und ausfuehrbar gemacht
deploy.envangelegt und angepasst (Pfade, Ports, Projekt-Namen)- Git-Hook oder Webhook eingerichtet (fuer automatisches Test-Deploy)
- Erster manueller Deploy-Test:
deploy-kbcrm-test.sh - Health-Check erfolgreich:
curl -k https://localhost:8443/health-check - Erster Prod-Deploy:
deploy-kbcrm-prod.sh - Health-Check erfolgreich:
curl -k https://localhost:443/health-check