refactor(deploy): remove old multi-resource code, document single docker-compose workflow
- Remove POSTGRES_COMPOSE, REDIS_COMPOSE templates (unused) - Remove create_service(), create_api_application(), generate_worker_compose() - Remove deploy_worker(), deploy_worker_only(), verify_worker_service() - Remove resolve_worker_uuid() and all worker_uuid references - Remove get_worker_envs(), get_api_envs(), get_postgres_envs(), get_redis_envs() - Remove set_service_envs(), set_application_envs() (dead code) - Remove _extract_deploy_uuid(), _wait_service_healthy() (only used by deploy_worker) - Remove seed_admin_user() (only used by old deploy_full) - Remove DB_HOST, REDIS_HOST, WORKER_UUID, WORKER_NAME config vars - Remove --worker-only CLI arg - Replace old deploy_full() with simple redeploy via /api/v1/deploy - Update run_verification() to remove worker_uuid param - Add KI workflow comment at top of deploy.py - Update DEPLOY.md: single docker-compose stack workflow - Update COOLIFY_SETUP.md: single docker-compose stack, remove 3-resource setup - Update docs/INSTALL.md: automated --initial workflow deploy.py: 1370 → 893 lines (-477 lines, -35%)
This commit is contained in:
@@ -1,39 +1,86 @@
|
||||
# LeoCRM Deployment
|
||||
|
||||
## Architektur
|
||||
|
||||
LeoCRM läuft als **einzelner docker-compose Stack** in Coolify. Alle 4 Container
|
||||
(PostgreSQL, Redis, API, Worker) werden aus der `docker-compose.yaml` im Git-Repo
|
||||
gestartet und teilen sich ein Docker-Netzwerk.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ Coolify Application (docker-compose) │
|
||||
│ ┌──────────┐ ┌──────────┐ │
|
||||
│ │ postgres │ │ redis │ │
|
||||
│ └────┬─────┘ └────┬─────┘ │
|
||||
│ │ │ │
|
||||
│ ┌────┴─────┐ ┌────┴─────┐ │
|
||||
│ │ crm_app │ │crm_worker│ │
|
||||
│ │ (API) │ │ (ARQ) │ │
|
||||
│ └──────────┘ └──────────┘ │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Keine separaten Coolify Services für DB/Redis/Worker. Alles in einem Stack.
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Option A: Coolify (empfohlen für Produktion)
|
||||
### Redeploy (bestehende Anwendung)
|
||||
|
||||
```bash
|
||||
# Einmalig: Umgebungsvariablen setzen
|
||||
# Umgebungsvariablen setzen
|
||||
export COOLIFY_API_TOKEN="dein-token"
|
||||
export COOLIFY_APP_UUID="dx4pqdziu4uj6x9fxs1u5z0x" # oder via APP_DOMAIN auto-resolved
|
||||
export APP_DOMAIN="https://crm.media-on.de"
|
||||
export COOLIFY_APP_UUID="dx4pqdziu4uj6x9fxs1u5z0x" # optional, wird via APP_NAME gesucht
|
||||
|
||||
# Deploy
|
||||
# Redeploy via Coolify API
|
||||
python scripts/deploy.py
|
||||
|
||||
# Redeploy (ohne Neubuild)
|
||||
python scripts/deploy.py --skip-build
|
||||
# Verifikation nur
|
||||
python scripts/deploy.py --verify-only
|
||||
```
|
||||
|
||||
Das Script macht automatisch:
|
||||
1. Coolify Build & Deploy triggern
|
||||
2. Persistent Volume in Coolify DB konfigurieren (automatisch, portabel)
|
||||
3. Auf healthy Container warten
|
||||
4. RLS auf allen Tenant-Tabellen sicherstellen
|
||||
5. DB-Migrationen verifizieren
|
||||
6. Worker-Container starten
|
||||
7. App-Health verifizieren
|
||||
8. Domain-Erreichbarkeit prüfen
|
||||
1. Coolify Application auflösen (via UUID oder Name)
|
||||
2. Deploy via `/api/v1/deploy` triggern
|
||||
3. Auf Deployment-Erfolg warten
|
||||
4. HTTP Health-Check verifizieren
|
||||
5. Login-Test (optional, wenn LOGIN_EMAIL/LOGIN_PASSWORD gesetzt)
|
||||
6. Alembic-Migration-Head prüfen (via SSH)
|
||||
7. RLS-Tabellen zählen (via SSH)
|
||||
|
||||
**Funktioniert auf jeder Coolify-Instanz. Bei mehreren Apps. Bei Erst-Deploy und Redeploy.**
|
||||
### Initial Deployment (neue Anwendung)
|
||||
|
||||
```bash
|
||||
# Alle Umgebungsvariablen setzen
|
||||
export COOLIFY_API_TOKEN="dein-token"
|
||||
export APP_DOMAIN="https://crm.media-on.de"
|
||||
export APP_NAME="leocrm" # Coolify Application Name
|
||||
export DB_PASSWORD="..."
|
||||
export REDIS_PASSWORD="..."
|
||||
export SECRET_KEY="..."
|
||||
export COOLIFY_PROJECT_UUID="..."
|
||||
export COOLIFY_SERVER_UUID="..."
|
||||
export COOLIFY_PRIVATE_KEY_UUID="..."
|
||||
export COOLIFY_ENVIRONMENT="production" # optional, default: production
|
||||
|
||||
# Initial deployment
|
||||
python scripts/deploy.py --initial
|
||||
```
|
||||
|
||||
Das Script macht automatisch:
|
||||
1. Coolify Application via `private-deploy-key` erstellen
|
||||
2. Build Pack auf `dockercompose` setzen (liest docker-compose.yaml aus Git)
|
||||
3. Environment-Variablen setzen (Secrets, Domain, Admin-Credentials)
|
||||
4. Erster Deploy (ohne Domain — Coolify muss docker-compose.yaml lesen)
|
||||
5. `docker_compose_domains` setzen + Redeploy (mit Traefik-Labels)
|
||||
6. Verifikation (HTTP, Login, Alembic, RLS)
|
||||
|
||||
### Option B: Docker Compose (lokal / ohne Coolify)
|
||||
|
||||
```bash
|
||||
# .env.docker erstellen
|
||||
cp .env.docker.example .env.docker
|
||||
$EDITOR .env.docker # SECRET_KEY, POSTGRES_PASSWORD, etc. ausfüllen
|
||||
$EDITOR .env.docker # SECRET_KEY, DB_PASSWORD, REDIS_PASSWORD etc. ausfüllen
|
||||
|
||||
# Starten (alle 4 Container: Postgres, Redis, App, Worker)
|
||||
docker compose --env-file .env.docker up --build -d
|
||||
@@ -46,19 +93,20 @@ docker compose down
|
||||
```
|
||||
|
||||
**Container:**
|
||||
- `crm-postgres` — PostgreSQL 16 mit pgvector
|
||||
- `crm-redis` — Redis 7
|
||||
- `crm-app` — FastAPI API Server
|
||||
- `crm-worker` — ARQ Background Worker
|
||||
- `postgres` — PostgreSQL 16 mit pgvector
|
||||
- `redis` — Redis 7
|
||||
- `crm_app` — FastAPI API Server
|
||||
- `crm_worker` — ARQ Background Worker
|
||||
|
||||
Alle mit persistenten Volumes. Kein Datenverlust bei Redeploy.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Python 3.12+
|
||||
- `httpx` Python package
|
||||
- Docker & Docker Compose (für Option B)
|
||||
- Coolify v4+ (für Option A)
|
||||
- SSH-Zugang zum Server (für Option A)
|
||||
- SSH-Zugang zum Server (für Verifikation, Option A)
|
||||
|
||||
## Umgebungsvariablen
|
||||
|
||||
@@ -66,13 +114,26 @@ Siehe `.env.example` für alle Variablen. Wichtigste:
|
||||
|
||||
| Variable | Pflicht | Default | Beschreibung |
|
||||
|---|---|---|---|
|
||||
| `DATABASE_URL` | Ja | — | PostgreSQL Connection String |
|
||||
| `REDIS_URL` | Ja | — | Redis Connection String |
|
||||
| `SECRET_KEY` | Ja | — | Mindestens 32 Zeichen |
|
||||
| `ENVIRONMENT` | Nein | `development` | `production` oder `development` |
|
||||
| `SESSION_COOKIE_SECURE` | Nein | `true` | In Production muss `true` |
|
||||
| `STORAGE_PATH` | Nein | `/data/storage` | Datei-Upload-Pfad |
|
||||
| `STORAGE_BACKEND` | Nein | `local` | `local` oder `s3` |
|
||||
| `COOLIFY_API_TOKEN` | Ja | — | Coolify API Token |
|
||||
| `APP_DOMAIN` | Ja | — | App-Domain (z.B. https://crm.media-on.de) |
|
||||
| `COOLIFY_APP_UUID` | Nein | — | Application UUID (auto-resolved via APP_NAME) |
|
||||
| `APP_NAME` | Nein | abgeleitet aus APP_DOMAIN | Coolify Application Name |
|
||||
| `SSH_KEY` | Nein | `/a0/usr/workdir/.ssh/coolify-01-root` | SSH Key für Verifikation |
|
||||
| `SERVER_IP` | Nein | `46.225.91.159` | Server IP für SSH |
|
||||
| `LOGIN_EMAIL` | Nein | — | Login-Test Email (optional) |
|
||||
| `LOGIN_PASSWORD` | Nein | — | Login-Test Passwort (optional) |
|
||||
|
||||
### Nur für `--initial`:
|
||||
|
||||
| Variable | Pflicht | Beschreibung |
|
||||
|---|---|---|
|
||||
| `DB_PASSWORD` | Ja | PostgreSQL Passwort |
|
||||
| `REDIS_PASSWORD` | Ja | Redis Passwort |
|
||||
| `SECRET_KEY` | Ja | Application Secret Key (min. 32 Zeichen) |
|
||||
| `COOLIFY_PROJECT_UUID` | Ja | Coolify Project UUID |
|
||||
| `COOLIFY_SERVER_UUID` | Ja | Coolify Server UUID |
|
||||
| `COOLIFY_PRIVATE_KEY_UUID` | Ja | Coolify Private Deploy Key UUID |
|
||||
| `COOLIFY_ENVIRONMENT` | Nein | Coolify Environment (default: production) |
|
||||
|
||||
## S3 Storage (optional)
|
||||
|
||||
@@ -85,19 +146,19 @@ S3_ACCESS_KEY=...
|
||||
S3_SECRET_KEY=...
|
||||
```
|
||||
|
||||
## Test- vs. Produktionsumgebung
|
||||
## Mehrere Instanzen
|
||||
|
||||
**Test:**
|
||||
Mehrere LeoCRM-Instanzen auf demselben Coolify-Server:
|
||||
```bash
|
||||
python scripts/deploy.py --environment test
|
||||
```
|
||||
Eigene Coolify-App, eigene DB, eigene Domain (`crm-test.media-on.de`).
|
||||
# Test-Instanz
|
||||
APP_NAME=leocrm-test APP_DOMAIN=https://crm-test.media-on.de python scripts/deploy.py --initial
|
||||
|
||||
**Produktion:**
|
||||
```bash
|
||||
python scripts/deploy.py --environment production
|
||||
# Produktions-Instanz
|
||||
APP_NAME=leocrm APP_DOMAIN=https://crm.media-on.de python scripts/deploy.py --initial
|
||||
```
|
||||
|
||||
Jede Instanz hat eigene DB, Redis, Container und Domain.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Container nicht healthy:**
|
||||
@@ -110,15 +171,10 @@ docker logs <container-name> --tail 50
|
||||
docker exec <container> alembic upgrade head
|
||||
```
|
||||
|
||||
**RLS nicht aktiv:**
|
||||
```bash
|
||||
python scripts/deploy.py --migrate-only
|
||||
```
|
||||
|
||||
**Worker nicht gestartet:**
|
||||
```bash
|
||||
python scripts/deploy.py --skip-build # startet Worker automatisch
|
||||
```
|
||||
**503 Fehler (Traefik):**
|
||||
- Domain ohne `:443` in `docker_compose_domains` setzen
|
||||
- Service-Namen mit Unterstrichen in docker-compose.yaml (crm_app, nicht crm-app)
|
||||
- `docker-compose.yaml` (nicht `.yml`) als Dateiname
|
||||
|
||||
## Backup & Restore
|
||||
|
||||
@@ -126,46 +182,34 @@ python scripts/deploy.py --skip-build # startet Worker automatisch
|
||||
|
||||
```bash
|
||||
# Full DB backup (run on the host or via docker exec)
|
||||
docker exec crm-postgres pg_dump -U crm_user -Fc crm_db > backup_$(date +%Y%m%d_%H%M%S).dump
|
||||
|
||||
# Backup mit Custom-Format (komprimiert, parallel restore-fähig)
|
||||
docker exec crm-postgres pg_dump -U crm_user -Fc -Z 9 crm_db > backup_$(date +%Y%m%d).dump
|
||||
docker exec <postgres-container> pg_dump -U crm_user -Fc crm_db > backup_$(date +%Y%m%d_%H%M%S).dump
|
||||
```
|
||||
|
||||
### Backup (Redis — Sessions/Queues)
|
||||
|
||||
```bash
|
||||
# Redis RDB Snapshot
|
||||
docker exec crm-redis redis-cli -a "$REDIS_PASSWORD" SAVE
|
||||
docker cp crm-redis:/data/dump.rdb redis_backup_$(date +%Y%m%d).rdb
|
||||
```
|
||||
|
||||
### Backup (File Storage)
|
||||
|
||||
```bash
|
||||
# Local storage volume
|
||||
docker run --rm -v leocrm-fix_storage:/data -v $(pwd):/backup alpine \
|
||||
tar czf /backup/storage_$(date +%Y%m%d).tar.gz /data
|
||||
docker exec <redis-container> redis-cli -a "$REDIS_PASSWORD" SAVE
|
||||
docker cp <redis-container>:/data/dump.rdb redis_backup_$(date +%Y%m%d).rdb
|
||||
```
|
||||
|
||||
### Restore (PostgreSQL)
|
||||
|
||||
```bash
|
||||
# Stop app containers
|
||||
docker compose stop crm-app crm-worker
|
||||
docker compose stop crm_app crm_worker
|
||||
|
||||
# Restore DB
|
||||
docker exec -i crm-postgres pg_restore -U crm_user -d crm_db --clean < backup_20260726.dump
|
||||
docker exec -i <postgres-container> pg_restore -U crm_user -d crm_db --clean < backup_20260726.dump
|
||||
|
||||
# Restart app
|
||||
docker compose start crm-app crm-worker
|
||||
docker compose start crm_app crm_worker
|
||||
```
|
||||
|
||||
### Automatisierte Backups (Cron)
|
||||
|
||||
```bash
|
||||
# /etc/cron.d/leocrm-backup
|
||||
0 2 * * * root docker exec crm-postgres pg_dump -U crm_user -Fc crm_db > /backups/leocrm_$(date +\%Y\%m\%d).dump
|
||||
0 2 * * * root docker exec <postgres-container> pg_dump -U crm_user -Fc crm_db > /backups/leocrm_$(date +\%Y\%m\%d).dump
|
||||
0 3 * * * root find /backups -name 'leocrm_*.dump' -mtime +30 -delete
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user