diff --git a/App_Server/Dockerfile b/App_Server/Dockerfile index bbd86c8..5332131 100644 --- a/App_Server/Dockerfile +++ b/App_Server/Dockerfile @@ -1,11 +1,8 @@ -ARG PYTHON_VERSION -ARG NODE_VERSION -ARG NPM_VERSION - # ── Stage: prod ────────────────────────────────────────────────── # Build-Context ist das Repo-Root (.), daher muessen alle COPY-Pfade # mit App_Server/ praefigiert werden. -FROM python:${PYTHON_VERSION} AS prod +# Python-Version fest im Dockerfile verankert — nicht per .env ueberschreibbar. +FROM python:slim-bookworm AS prod RUN ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime RUN apt-get clean && apt-get update && apt-get install -y locales RUN echo "de_DE.UTF-8 UTF-8" >> /etc/locale.gen @@ -30,8 +27,7 @@ ENTRYPOINT ["sh", "/usr/opt/pythonapp/App_Server/scripts/init.sh"] # ── Stage: dev ─────────────────────────────────────────────────── FROM prod AS dev -ARG NODE_VERSION -ARG NPM_VERSION +# Node.js-Version fest im Dockerfile verankert. # --- 2. Systemabhängigkeiten (für Python + Node.js) --- RUN apt-get update && \ @@ -49,9 +45,9 @@ RUN apt-get update && \ && rm -rf /var/lib/apt/lists/* # --- 3. Node.js + npm installieren --- -RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - && \ +RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && \ apt-get install -y nodejs && \ - npm install -g npm@${NPM_VERSION} + npm install -g npm@latest # --- 4. Dev-Start-Script kopieren (fuer Konsistenz, wird sonst per bind-mount bereitgestellt) --- COPY App_Server/scripts/inittypescriptdev.sh /usr/opt/pythonapp/App_Server/scripts/inittypescriptdev.sh diff --git a/Dokumentationen/Deployment-Anleitung.md b/Dokumentationen/Deployment-Anleitung.md new file mode 100644 index 0000000..54d4b10 --- /dev/null +++ b/Dokumentationen/Deployment-Anleitung.md @@ -0,0 +1,422 @@ +# 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 gesamte Code (Python + TypeScript) in das Docker-Image + gebaut. 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). +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 + +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) | +| `NGINX_CERT` | ja | Zertifikatsdatei | +| `NGINX_CERT_KEY` | ja | Privater Schluessel | +| `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 | + +--- + +## 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` diff --git a/NGINX_Server/Dockerfile b/NGINX_Server/Dockerfile index 14763a7..6662e47 100644 --- a/NGINX_Server/Dockerfile +++ b/NGINX_Server/Dockerfile @@ -1,10 +1,6 @@ -ARG NGINX_VERSION -ARG NODE_VERSION -ARG NPM_VERSION - # ── Stage: frontend — baut das TypeScript-JS-Bundle ────────────── # Node.js, npm und node_modules landen NICHT im Prod-Image. -FROM node:${NODE_VERSION}-bookworm-slim AS frontend +FROM node:lts-bookworm-slim AS frontend # Zielverzeichnis fuer rollup-Output erstellen (absoluter Pfad wie in rollup.config.mjs) RUN mkdir -p /usr/opt/pythonapp/NGINX_Server/html/static WORKDIR /usr/opt/pythonapp/Client @@ -19,7 +15,7 @@ COPY App_Server/root/config.ini /usr/opt/pythonapp/App_Server/root/config.ini RUN npm run build # ── Stage: nginx ──────────────────────────────────────────────── -FROM nginx:${NGINX_VERSION} +FROM nginx:mainline-alpine RUN ln -sf /usr/share/zoneinfo/Europe/Berlin /etc/localtime RUN mkdir -p /etc/certs /etc/nginx/templates COPY NGINX_Server/10-select-ssl.sh /docker-entrypoint.d/10-select-ssl.sh diff --git a/docker-compose.base.yaml b/docker-compose.base.yaml index 7f97777..258a375 100644 --- a/docker-compose.base.yaml +++ b/docker-compose.base.yaml @@ -4,11 +4,6 @@ services: build: context: . # Repo-Root (fuer frontend-Stage im NGINX-Dockerfile) dockerfile: NGINX_Server/Dockerfile # explizit, da Context nicht mehr NGINX_Server/ - args: - NGINX_VERSION: ${NGINX_VERSION} - NODE_VERSION: ${NODE_VERSION} - NPM_VERSION: ${NPM_VERSION} - ports: - ${NGINX_HOST_PORT}:4430 volumes: @@ -25,10 +20,6 @@ services: build: context: . # Repo-Root (fuer COPY-Pfade im Dockerfile) dockerfile: App_Server/Dockerfile # explizit, da Context nicht mehr App_Server/ - args: - PYTHON_VERSION: ${PYTHON_VERSION} - NODE_VERSION: ${NODE_VERSION} # fuer dev-Stage - NPM_VERSION: ${NPM_VERSION} # fuer dev-Stage volumes: - ${PYTHON_DB_DIR}:/usr/var/pythonappdb # python-venv Volume entfaellt — venv ist im Image diff --git a/docker-compose.dev.yaml b/docker-compose.dev.yaml index 859f58f..0e2c27e 100644 --- a/docker-compose.dev.yaml +++ b/docker-compose.dev.yaml @@ -6,9 +6,6 @@ services: service: pythonapp build: target: dev - args: - NODE_VERSION: ${NODE_VERSION:-18} - NPM_VERSION: ${NPM_VERSION:-8} environment: # Globales Vibe-Home innerhalb des Workspace-Bind-Mounts, damit es auf dem Host persistiert - VIBE_HOME=/usr/opt/pythonapp/.vibe-global diff --git a/env-sample b/env-sample index 06318a8..318e9bc 100644 --- a/env-sample +++ b/env-sample @@ -8,7 +8,6 @@ BUILD_ENVIRONMENT=dev COMPOSE_FILE=docker-compose.base.yaml:docker-compose.${BUILD_ENVIRONMENT}.yaml # Parameter für NGINX-Server -NGINX_VERSION=mainline-alpine # SSL für NGINX aktivieren (true) oder deaktivieren (false). # Bei false muss NGINX_HOST_PORT angepasst werden (z.B. 8080 statt 443). NGINX_USE_SSL=true @@ -25,16 +24,12 @@ NGINX_CERT=wildcard.mylocal.crt NGINX_CERT_KEY=wildcard.mylocal.key # Parameter for Python App-Server -PYTHON_VERSION=slim-bookworm # PYTHON_APP_DIR entfaellt — Code wird in Prod ins Image gebaut (Option B). # In Dev wird PYTHON_DEV_DIR als bind-mount verwendet (siehe docker-compose.dev.yaml). PYTHON_DEV_DIR=/home/schoschi/Entwicklung/Projekte_Runden/kbcrm PYTHON_DB_DIR=/home/schoschi/Entwicklung/Projekte_Runden/kbcrm/App_Server/data # PYTHON_ENV_DIR=/home/schoschi/Entwicklung/Projekte_Runden/kbcrm/App_Server/env -# Parameter für Dev-Mode (Development-Container für VS-Code) -NODE_VERSION=lts -NPM_VERSION=latest # ============================================================================= # ZITADEL OIDC SETTINGS