# 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 push` auf `main` loest 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`, `docker` und `docker 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`). --- ## 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 │ └── .env ← test-prod Umgebung (eigene Ports, eigene DB) ├── prod/ │ ├── repo/ │ └── .env ← prod Umgebung └── scripts/ ├── deploy-kbcrm-test.sh ← aus dem Repo (scripts/) └── deploy-kbcrm-prod.sh ← aus dem Repo (scripts/) ``` 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 ```bash sudo mkdir -p /opt/kbcrm/test-prod /opt/kbcrm/prod # Test-Prod Repository sudo git clone https://git.everdc.eu/chmln-app-dev/kbcrm /opt/kbcrm/test-prod/repo # Prod Repository sudo git clone https://git.everdc.eu/chmln-app-dev/kbcrm /opt/kbcrm/prod/repo ``` ### 4.2. `.env`-Dateien anlegen Kopieren Sie die Vorlage aus dem Repo und passen Sie die Werte an: ```bash # Test-Prod cp /opt/kbcrm/test-prod/repo/env-sample /opt/kbcrm/test-prod/.env # Prod cp /opt/kbcrm/prod/repo/env-sample /opt/kbcrm/prod/.env ``` ### 4.3. `.env` fuer Test-Prod anpassen ```bash vi /opt/kbcrm/test-prod/.env ``` Folgende Einstellungen muessen angepasst werden: ```bash # 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= ZITADEL_CLIENT_SECRET= ZITADEL_REDIRECT_URI=https://test.kbp_crm.mylocal.de/auth/callback ``` ### 4.4. `.env` fuer Prod anpassen ```bash vi /opt/kbcrm/prod/.env ``` ```bash 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 ```bash 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: ```bash 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: ```bash 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/prod/repo/scripts/deploy-kbcrm-prod.sh /opt/kbcrm/scripts/ sudo chmod +x /opt/kbcrm/scripts/*.sh ``` Passen Sie die Pfad-Variablen am Anfang der Scripts an, falls Ihre Verzeichnisstruktur abweicht. --- ## 5. Git-Hook einrichten (automatisches Test-Deploy) ### Variante A: post-receive Hook (direkt auf dem Git-Server) Wenn Shell-Zugang zum Git-Server besteht: ```bash # Auf dem Git-Server, im bare Repository: vi /srv/git/kbcrm.git/hooks/post-receive ``` ```bash #!/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 ``` ```bash chmod +x /srv/git/kbcrm.git/hooks/post-receive ``` ### Variante B: Webhook (empfohlen fuer Gitea) 1. In Gitea: Repository-Einstellungen -> Webhooks -> Webhook hinzufuegen 2. URL: `http://deploy-server:9000/webhook` (Beispiel) 3. Content-Type: `application/json` 4. Trigger: "Push Events" (nur auf `main`) 5. 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): ```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: ```ini # /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 ``` ```bash 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: ```bash /opt/kbcrm/scripts/deploy-kbcrm-test.sh ``` Das Script fuehrt folgende Schritte aus: 1. `git pull` (latest main) 2. `docker compose up -d --build` (baut beide Images: NGINX mit TypeScript- Build und Python mit Anwendungscode) 3. Health-Check ### 6.2. Manuelle Promotion nach Prod Nach Verifikation auf dem Test-Server: ```bash /opt/kbcrm/scripts/deploy-kbcrm-prod.sh ``` Das Script fragt eine Bestaetigung ("yes/no") und fuehrt dann den gleichen Ablauf aus wie das Test-Script, jedoch mit der Prod-`.env`. ### 6.3. Alternative: Git-Tag-basierte Promotion Statt das Prod-Script manuell aufzurufen, kann ein Git-Tag das Prod-Deploy ausloesen: ```bash # 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: ```bash #!/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 ```bash # Test-Prod docker compose --env-file /opt/kbcrm/test-prod/.env \ -f /opt/kbcrm/test-prod/repo/docker-compose.prod.yaml logs # Prod docker compose --env-file /opt/kbcrm/prod/.env \ -f /opt/kbcrm/prod/repo/docker-compose.prod.yaml logs # Nur Python-Container docker compose --env-file /opt/kbcrm/prod/.env \ -f /opt/kbcrm/prod/repo/docker-compose.prod.yaml logs pythonapp # Nur NGINX-Container docker compose --env-file /opt/kbcrm/prod/.env \ -f /opt/kbcrm/prod/repo/docker-compose.prod.yaml logs nginx-proxy ``` ### Container-Status pruefen ```bash docker compose --env-file /opt/kbcrm/prod/.env \ -f /opt/kbcrm/prod/repo/docker-compose.prod.yaml ps ``` ### Manuell in den Container wechseln ```bash docker compose --env-file /opt/kbcrm/prod/.env \ -f /opt/kbcrm/prod/repo/docker-compose.prod.yaml exec pythonapp bash ``` ### Rollback Bei Problemen kann auf einen frueheren Stand zurueckgekehrt werden: ```bash # Auf dem Deploy-Server: cd /opt/kbcrm/prod/repo git log --oneline -10 # frueheren Commit finden git checkout docker compose --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: ```bash 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: ```bash 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 - [ ] 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`