spawner/MVP_DEPLOYMENT_GUIDE.md
XPS\Micro 2bcb7b97a4 docs: add comprehensive MVP deployment guide
Add step-by-step deployment instructions covering:
- Phase 1: Preparation (clean slate, build templates, configure env)
- Phase 2: Start services (docker-compose up, health checks)
- Phase 3: First registration (test user creation)
- Phase 4: Test both containers (dev and prod)

Includes:
- Verification checklist for backend, frontend, docker, traefik
- Detailed troubleshooting guide for common issues
- Monitoring and status commands
- Security checklist for production
- Performance scaling recommendations
- Next phase features for enhancement

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-01-31 20:33:57 +01:00

12 KiB

Multi-Container MVP - Deployment Guide

🎯 Überblick

Das Multi-Container MVP implementiert Unterstützung für 2 Container-Typen pro User:

  • Development (dev): Nginx mit einfacher Willkommensseite
  • Production (prod): Next.js mit Shadcn/UI

Jeder Benutzer kann beide Container independent verwalten über das Dashboard.


📋 Voraussetzungen

  • Docker & Docker Compose
  • Python 3.11+
  • Node.js 18+ (für Frontend)
  • Traefik als Reverse Proxy mit Docker Provider

🚀 Deployment-Anleitung

Phase 1: Vorbereitung (15 Minuten)

1.1 Code auschecken

git pull origin main

1.2 Alte Daten bereinigen (CLEAN SLATE)

# Alle alten User-Container stoppen
docker ps -a | grep "user-" | awk '{print $1}' | xargs docker rm -f 2>/dev/null || true

# Alte Datenbank löschen
rm -f spawner.db

# Logs löschen
rm -rf logs/*

1.3 Template-Images bauen

# Development Template (Nginx)
docker build -t user-service-template:latest user-template/

# Production Template (Next.js)
docker build -t user-template-next:latest user-template-next/

# Überprüfung
docker images | grep user-

Erwartet Output:

user-service-template     latest    abc123...    5 minutes ago   100MB
user-template-next        latest    def456...    3 minutes ago   250MB

1.4 Environment konfigurieren

# Copy beispiel Datei
cp .env.example .env

# Bearbeite .env und passe an:
nano .env

Erforderliche Änderungen in .env:

# Neue Zeilen hinzufügen oder bestehende aktualisieren:
SECRET_KEY=<generiert mit: python3 -c "import secrets; print(secrets.token_hex(32))">
BASE_DOMAIN=yourdomain.com
SPAWNER_SUBDOMAIN=coder
TRAEFIK_NETWORK=web
TRAEFIK_CERTRESOLVER=lets-encrypt
TRAEFIK_ENTRYPOINT=websecure

# Multi-Container Templates (NEU!)
USER_TEMPLATE_IMAGE_DEV=user-service-template:latest
USER_TEMPLATE_IMAGE_PROD=user-template-next:latest

# Optional: SMTP für Magic Links
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USER=noreply@example.com
SMTP_PASSWORD=password
SMTP_FROM=noreply@example.com
FRONTEND_URL=https://coder.yourdomain.com

Phase 2: Services starten (10 Minuten)

2.1 Docker Compose starten

docker-compose up -d --build

# Warte bis Services bereit sind
sleep 10

# Überprüfe Status
docker-compose ps

Erwartet Output:

NAME                STATUS              PORTS
spawner             Up X seconds        5000/tcp
frontend            Up X seconds        3000/tcp
traefik             Up X seconds        80/tcp, 443/tcp, 8080/tcp

2.2 Logs prüfen

# Backend Logs
docker-compose logs spawner | tail -20

# Frontend Logs
docker-compose logs frontend | tail -20

# Traefik Logs
docker-compose logs traefik | tail -20

Wichtig: Suche nach ERROR-Meldungen. Häufige Fehler:

  • docker.errors.ImageNotFound: Template-Images nicht gebaut
  • ConnectionRefusedError: Backend nicht erreichbar
  • CORS error: CORS_ORIGINS nicht konfiguriert

2.3 Health Check

# Backend Health
curl -s http://localhost:5000/health | jq .

# Frontend (falls lokal erreichbar)
curl -s http://localhost:3000 | head -20

Phase 3: Erste Registrierung (5 Minuten)

3.1 Öffne Dashboard

https://coder.yourdomain.com

3.2 Registrierung

  1. Klick auf "Registrieren"
  2. Gib Email-Adresse ein: test@yourdomain.com
  3. Klick "Magic Link senden"
  4. Überprüfe Email (oder Logs für Magic Link Token wenn SMTP nicht konfiguriert)
  5. Klick auf Magic Link in Email
  6. Du wirst zum Dashboard weitergeleitet

3.3 Dashboard überprüfen

  • 2 Container-Cards sichtbar (Dev und Prod)
  • Beide haben Status "Noch nicht erstellt"
  • Buttons zeigen "Erstellen & Öffnen"

Phase 4: Teste beide Container (10 Minuten)

4.1 Development Container erstellen

Dashboard: Dev Container Card → Click "Erstellen & Öffnen"

Erwartet:
1. Loading-Spinner erscheint
2. Neuer Browser-Tab öffnet sich
3. URL: https://coder.yourdomain.com/test-dev (mit deinem slug)
4. Nginx-Willkommensseite wird angezeigt

4.2 Dashboard aktualisieren

Zurück zum Spawner-Tab

Erwartet:
1. Dev-Container Status = "Läuft"
2. Button ändert sich zu "Service öffnen"
3. Last-Used Timestamp wird angezeigt

4.3 Production Container erstellen

Dashboard: Prod Container Card → Click "Erstellen & Öffnen"

Erwartet:
1. Loading-Spinner erscheint
2. Neuer Browser-Tab öffnet sich
3. URL: https://coder.yourdomain.com/test-prod (mit deinem slug)
4. Next.js Demo-Seite mit Shadcn/UI wird angezeigt

4.4 Beide Containers öffnen

Dashboard: Click "Service öffnen" für Dev-Container
→ Öffnet Dev-Container in bestehendem/neuem Tab

Dashboard: Click "Service öffnen" für Prod-Container
→ Öffnet Prod-Container in bestehendem/neuem Tab

Beide sollten funktionieren, ohne /dev oder /prod in der URL!

🔍 Verification Checklist

Backend

  • spawner Container läuft (docker ps | grep spawner)
  • Flask Server startet ohne Fehler (docker-compose logs spawner | grep "Running on")
  • UserContainer Tabelle existiert (docker exec spawner sqlite3 /app/data/users.db ".schema user_container")
  • GET /api/user/containers gibt 2 Containers zurück (mit Status "not_created")
  • POST /api/container/launch/dev funktioniert und erstellt Container

Frontend

  • Dashboard lädt beide Container-Cards
  • API-Calls funktionieren (Browser DevTools → Network Tab)
  • Buttons sind nicht disabled
  • Loading State erscheint beim Klick
  • URLs öffnen sich in neuem Tab

Docker & Traefik

  • docker ps | grep user- zeigt 2 Container nach Launch
  • Traefik Dashboard zeigt 2 HTTP Routers (für dev und prod)
  • StripPrefix entfernt /{slug}-{type} korrekt
  • Beide Containers sind erreichbar ohne /dev oder /prod in der URL

URLs

  • https://coder.yourdomain.com/{slug}-dev → Dev-Container
  • https://coder.yourdomain.com/{slug}-prod → Prod-Container
  • Keine 404 oder CORS-Fehler in Browser Console

🐛 Troubleshooting

Problem: Container spawnt nicht

Symptom: Klick auf "Erstellen & Öffnen" → Fehler "Container konnte nicht erstellt werden"

Lösung:

# 1. Überprüfe Logs
docker-compose logs spawner | tail -50

# 2. Überprüfe ob Images existieren
docker images | grep user-

# 3. Falls nicht vorhanden, baue neu:
docker build -t user-service-template:latest user-template/
docker build -t user-template-next:latest user-template-next/

# 4. Starte Services neu
docker-compose restart spawner

Problem: URL öffnet nicht / 404 Error

Symptom: Browser zeigt 404 oder Timeout beim Klick "Service öffnen"

Lösung:

# 1. Überprüfe Container läuft
docker ps | grep user-testuser-dev

# 2. Überprüfe Traefik Dashboard
curl http://localhost:8080/api/http/routers | grep user

# 3. Überprüfe Container-Labels
docker inspect user-testuser-dev-1 | grep -A5 "traefik"

# 4. Falls Labels falsch, starte Services neu
docker-compose restart

# 5. Überprüfe Traefik Logs
docker-compose logs traefik | grep user

Problem: StripPrefix funktioniert nicht

Symptom: Container erhält Path mit /{slug}-dev noch darin

Lösung:

# 1. Prüfe Traefik Middleware
curl http://localhost:8080/api/http/middlewares | jq . | grep -A10 "user"

# 2. Container sollte bei / landen, nicht bei /{slug}-dev
curl -H "Host: coder.yourdomain.com" \
  "http://localhost:8080/testuser-dev/this/is/a/test"
# Sollte zu Container weitergeleitet werden mit Path: /this/is/a/test

# 3. Falls Problem persistiert, rebuild Traefik
docker-compose down
docker-compose up -d --build traefik

Symptom: Email wird nicht empfangen oder Link funktioniert nicht

Lösung:

# 1. Überprüfe SMTP Konfiguration
docker-compose logs spawner | grep -i smtp

# 2. Falls SMTP nicht konfiguriert, überprüfe Logs für Token
docker-compose logs spawner | grep "Magic Link" | tail -5

# 3. Kopiere Token manuell aus Logs und öffne URL:
# https://coder.yourdomain.com/verify-signup?token=ABC123...

# 4. Zum Testen ohne SMTP:
# Setze SMTP_HOST=localhost im .env
# Tokens werden dann nur in Logs ausgegeben

Problem: Frontend kann nicht mit Backend kommunizieren

Symptom: CORS-Fehler oder "Netzwerkfehler"

Lösung:

# 1. Überprüfe CORS_ORIGINS in Backend
docker exec spawner grep CORS_ORIGINS /app/.env

# 2. Sollte enthalten: https://coder.yourdomain.com (oder http://localhost:3000 in Dev)

# 3. Falls nicht richtig gesetzt:
# Bearbeite .env und setze:
CORS_ORIGINS=https://coder.yourdomain.com

# 4. Restart Backend
docker-compose restart spawner

# 5. Browser Cache löschen und Seite neu laden

📊 Monitoring

Logs überwachen

# Alle Services
docker-compose logs -f

# Nur Backend
docker-compose logs -f spawner

# Traefik
docker-compose logs -f traefik

# Frontend
docker-compose logs -f frontend

Container Status

# Alle Container
docker ps

# Mit Filter
docker ps | grep user-

# Detailed Info
docker inspect user-testuser-dev-1

Traefik Status

# Routers
curl http://localhost:8080/api/http/routers

# Middlewares
curl http://localhost:8080/api/http/middlewares

# Services
curl http://localhost:8080/api/http/services

Datenbank prüfen

# Container-Liste
docker exec spawner sqlite3 /app/data/users.db \
  "SELECT id, user_id, container_type, container_id FROM user_container LIMIT 10;"

# User-Liste
docker exec spawner sqlite3 /app/data/users.db \
  "SELECT id, email, slug, state FROM user LIMIT 10;"

🔐 Security Checklist

  • SECRET_KEY ist generiert und komplex
  • JWT_SECRET_KEY ist gesetzt (oder nutzt SECRET_KEY)
  • CORS_ORIGINS ist auf richtige Domain gesetzt
  • SMTP_PASSWORD ist nicht im .env.example hart-codiert
  • Database-URL nutzt keine Standardpasswörter (für Production)
  • Traefik Let's Encrypt Email ist gesetzt
  • TLS ist aktiviert für alle Routes
  • Container-Ressource Limits sind gesetzt (Memory, CPU)

📈 Scaling & Performance

Single User Multiple Containers

  • Pro User können 2 Container laufen (dev und prod)
  • Jeder Container: 512MB RAM, 0.5 CPU (konfigurierbar)
  • Für 100 User: Max 1GB RAM pro Container = 200GB total (nicht realistisch!)

Production Empfehlungen

  • Datenbank: Wechsel auf PostgreSQL (in config.py kommentiert)
  • Storage: Persistente Volumes für Container-Daten
  • Backups: Regelmäßige Backups der Datenbank und User-Volumes
  • Monitoring: Prometheus + Grafana für Metrics
  • Logging: Centralized Logging (ELK, Loki)

Load Testing

# Einfacher Test mit 10 gleichzeitigen Containern
for i in {1..10}; do
  docker run -d \
    --network web \
    --label "test=true" \
    user-service-template:latest
done

# Überwachen
docker stats | grep "test"

# Cleanup
docker ps --filter "label=test=true" | xargs docker rm -f

🎓 Nächste Schritte

Phase 1: MVP Live

  • 2 Container-Typen (dev, prod)
  • On-Demand Erstellung
  • Multi-Container Dashboard
  • Status-Tracking

Phase 2: Enhancements (Optional)

  • Container-Logs im Dashboard
  • Container-Restart pro Type
  • Resource-Monitoring
  • Container-Cleanup (Idle Timeout)
  • Custom Templates vom User

Phase 3: Admin Features (Optional)

  • Container-Management im Admin-Panel
  • User-Quotas pro Container-Typ
  • Template-Updates ohne Service-Restart
  • Audit Logging für Container-Events

📞 Support & Dokumentation

Wichtige Dateien

  • IMPLEMENTATION_SUMMARY.md - Detaillierte Feature-Liste
  • TEST_VERIFICATION.md - Test-Anleitung
  • CLAUDE.md - Projekt-Übersicht
  • docker-compose.yml - Service-Konfiguration
  • .env.example - Environment-Template

Häufig benötigte Commands

# Status überprüfen
docker-compose ps

# Logs anschauen
docker-compose logs -f [service]

# Services neu starten
docker-compose restart [service]

# Container in Python Shell bearbeiten
docker exec -it spawner python

# Datenbank migrieren
docker exec spawner flask db migrate
docker exec spawner flask db upgrade

# Admin-User erstellen
docker exec -it spawner python <<EOF
from app import app, db
from models import User
with app.app_context():
    user = User(email='admin@example.com', slug='admin')
    user.is_admin = True
    user.state = 'verified'
    db.session.add(user)
    db.session.commit()
EOF

Version: 1.0.0 (MVP) Deployment Date: 2025-01-31 Last Updated: 2025-01-31 Status: Ready for Production