ARG-Variablen durch feste Werte in FROM ersetzt — nicht per .env ueberschreibbar. PYTHON_VERSION, NODE_VERSION, NPM_VERSION, NGINX_VERSION aus .env, env-sample und Compose-Dateien entfernt. Deployment-Anleitung erstellt und entsprechend angepasst. Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
423 lines
12 KiB
Markdown
423 lines
12 KiB
Markdown
# 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=<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
|
|
|
|
```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 <commit-hash>
|
|
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`
|