Zum Inhalt

CI/CD Pipeline

Übersicht über den Deployment-Prozess für Breakpilot.

Übersicht

Komponente Build-Tool Deployment
Frontend (Next.js) Docker Mac Mini
Backend (FastAPI) Docker Mac Mini
Go Services Docker (Multi-stage) Mac Mini
Documentation MkDocs Docker (Nginx)

Deployment-Architektur

┌─────────────────────────────────────────────────────────────────┐
│                      Entwickler-MacBook                          │
│                                                                   │
│   breakpilot-pwa/                                                │
│   ├── studio-v2/          (Next.js Frontend)                    │
│   ├── admin-v2/           (Next.js Admin)                       │
│   ├── backend/            (Python FastAPI)                       │
│   ├── consent-service/    (Go Service)                          │
│   ├── klausur-service/    (Python FastAPI)                      │
│   ├── voice-service/      (Python FastAPI)                      │
│   ├── ai-compliance-sdk/  (Go Service)                          │
│   └── docs-src/           (MkDocs)                              │
│                                                                   │
│   $ ./sync-and-deploy.sh                                         │
└───────────────────────────────┬─────────────────────────────────┘
                                │ rsync + SSH
┌─────────────────────────────────────────────────────────────────┐
│                         Mac Mini Server                          │
│                                                                   │
│   Docker Compose                                                 │
│   ├── website (Port 3000)                                       │
│   ├── studio-v2 (Port 3001)                                     │
│   ├── admin-v2 (Port 3002)                                      │
│   ├── backend (Port 8000)                                       │
│   ├── consent-service (Port 8081)                               │
│   ├── klausur-service (Port 8086)                               │
│   ├── voice-service (Port 8082)                                 │
│   ├── ai-compliance-sdk (Port 8090)                             │
│   ├── docs (Port 8009)                                          │
│   ├── postgres                                                   │
│   ├── valkey (Redis)                                            │
│   ├── qdrant                                                     │
│   └── minio                                                      │
│                                                                   │
└─────────────────────────────────────────────────────────────────┘

Sync & Deploy Workflow

1. Dateien synchronisieren

# Sync aller relevanten Verzeichnisse zum Mac Mini
rsync -avz --delete \
  --exclude 'node_modules' \
  --exclude '.next' \
  --exclude '.git' \
  --exclude '__pycache__' \
  --exclude 'venv' \
  --exclude '.pytest_cache' \
  /Users/benjaminadmin/Projekte/breakpilot-pwa/ \
  macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/

2. Container bauen

# Einzelnen Service bauen
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  build --no-cache <service-name>"

# Beispiele:
# studio-v2, admin-v2, website, backend, klausur-service, docs

3. Container deployen

# Container neu starten
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  up -d <service-name>"

4. Logs prüfen

# Container-Logs anzeigen
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  logs -f <service-name>"

Service-spezifische Deployments

Next.js Frontend (studio-v2, admin-v2, website)

# 1. Sync
rsync -avz --delete \
  --exclude 'node_modules' --exclude '.next' --exclude '.git' \
  /Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/ \
  macmini:/Users/benjaminadmin/Projekte/breakpilot-pwa/studio-v2/

# 2. Build & Deploy
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  build --no-cache studio-v2 && \
  /usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  up -d studio-v2"

Python Services (backend, klausur-service, voice-service)

# Build mit requirements.txt
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  build klausur-service && \
  /usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  up -d klausur-service"
# Multi-stage Build (Go → Alpine)
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  build --no-cache consent-service && \
  /usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  up -d consent-service"

MkDocs Dokumentation

# Build & Deploy
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  build --no-cache docs && \
  /usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  up -d docs"

# Verfügbar unter: http://macmini:8009

Health Checks

Service-Status prüfen

# Alle Container-Status
ssh macmini "docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'"

# Health-Endpoints prüfen
curl -s http://macmini:8000/health
curl -s http://macmini:8081/health
curl -s http://macmini:8086/health
curl -s http://macmini:8090/health

Logs analysieren

# Letzte 100 Zeilen
ssh macmini "docker logs --tail 100 breakpilot-pwa-backend-1"

# Live-Logs folgen
ssh macmini "docker logs -f breakpilot-pwa-backend-1"

Rollback

Container auf vorherige Version zurücksetzen

# 1. Aktuelles Image taggen
ssh macmini "docker tag breakpilot-pwa-backend:latest breakpilot-pwa-backend:backup"

# 2. Altes Image deployen
ssh macmini "/usr/local/bin/docker compose \
  -f /Users/benjaminadmin/Projekte/breakpilot-pwa/docker-compose.yml \
  up -d backend"

# 3. Bei Problemen: Backup wiederherstellen
ssh macmini "docker tag breakpilot-pwa-backend:backup breakpilot-pwa-backend:latest"

Troubleshooting

Container startet nicht

# 1. Logs prüfen
ssh macmini "docker logs breakpilot-pwa-<service>-1"

# 2. Container manuell starten für Debug-Output
ssh macmini "docker compose -f .../docker-compose.yml run --rm <service>"

# 3. In Container einloggen
ssh macmini "docker exec -it breakpilot-pwa-<service>-1 /bin/sh"

Port bereits belegt

# Port-Belegung prüfen
ssh macmini "lsof -i :8000"

# Container mit dem Port finden
ssh macmini "docker ps --filter publish=8000"

Build-Fehler

# Cache komplett leeren
ssh macmini "docker builder prune -a"

# Ohne Cache bauen
ssh macmini "docker compose build --no-cache <service>"

Monitoring

Resource-Nutzung

# CPU/Memory aller Container
ssh macmini "docker stats --no-stream"

# Disk-Nutzung
ssh macmini "docker system df"

Cleanup

# Ungenutzte Images/Container entfernen
ssh macmini "docker system prune -a --volumes"

# Nur dangling Images
ssh macmini "docker image prune"

Umgebungsvariablen

Umgebungsvariablen werden über .env Dateien und docker-compose.yml verwaltet:

# docker-compose.yml
services:
  backend:
    environment:
      - DATABASE_URL=postgresql://...
      - REDIS_URL=redis://valkey:6379
      - SECRET_KEY=${SECRET_KEY}

Wichtig: Sensible Werte niemals in Git committen. Stattdessen: - .env Datei auf dem Server pflegen - Secrets über HashiCorp Vault (siehe unten)

Woodpecker CI - Automatisierte OAuth Integration

Überblick

Die OAuth-Integration zwischen Woodpecker CI und Gitea ist vollständig automatisiert. Credentials werden in HashiCorp Vault gespeichert und bei Bedarf automatisch regeneriert.

Warum automatisiert?

Diese Automatisierung ist eine DevSecOps Best Practice:

  • Infrastructure-as-Code: Alles ist reproduzierbar
  • Disaster Recovery: Verlorene Credentials können automatisch regeneriert werden
  • Security: Secrets werden zentral in Vault verwaltet
  • Onboarding: Neue Entwickler müssen nichts manuell konfigurieren

Architektur

┌─────────────────────────────────────────────────────────────────┐
│                        Mac Mini Server                           │
│                                                                   │
│   ┌───────────────┐         OAuth 2.0         ┌───────────────┐ │
│   │    Gitea      │ ←─────────────────────────→│  Woodpecker   │ │
│   │  (Port 3003)  │    Client ID + Secret     │  (Port 8090)  │ │
│   └───────────────┘                           └───────────────┘ │
│          │                                            │         │
│          │ OAuth App                                  │ Env Vars│
│          │ (DB: oauth2_application)                   │         │
│          │                                            │         │
│          ▼                                            ▼         │
│   ┌───────────────────────────────────────────────────────────┐ │
│   │                 HashiCorp Vault (Port 8200)                │ │
│   │                                                             │ │
│   │   secret/cicd/woodpecker:                                  │ │
│   │     - gitea_client_id                                      │ │
│   │     - gitea_client_secret                                  │ │
│   │                                                             │ │
│   │   secret/cicd/api-tokens:                                  │ │
│   │     - gitea_token (für API-Zugriff)                       │ │
│   │     - woodpecker_token (für Pipeline-Trigger)             │ │
│   └───────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘

Credentials-Speicherorte

Ort Pfad Inhalt
HashiCorp Vault secret/cicd/woodpecker Client ID + Secret (Quelle der Wahrheit)
.env Datei WOODPECKER_GITEA_CLIENT/SECRET Für Docker Compose (aus Vault geladen)
Gitea PostgreSQL oauth2_application Tabelle OAuth App Registration (gehashtes Secret)

Troubleshooting: OAuth Fehler

Falls der Fehler "Client ID not registered" oder "user does not exist [uid: 0]" auftritt:

# Option 1: Automatisches Regenerieren (empfohlen)
./scripts/sync-woodpecker-credentials.sh --regenerate

# Option 2: Manuelles Vorgehen
# 1. Credentials aus Vault laden
vault kv get secret/cicd/woodpecker

# 2. .env aktualisieren
WOODPECKER_GITEA_CLIENT=<client_id>
WOODPECKER_GITEA_SECRET=<client_secret>

# 3. Zu Mac Mini synchronisieren
rsync .env macmini:~/Projekte/breakpilot-pwa/

# 4. Woodpecker neu starten
ssh macmini "cd ~/Projekte/breakpilot-pwa && \
  docker compose up -d --force-recreate woodpecker-server"

Das Sync-Script

Das Script scripts/sync-woodpecker-credentials.sh automatisiert den gesamten Prozess:

# Credentials aus Vault laden und .env aktualisieren
./scripts/sync-woodpecker-credentials.sh

# Neue Credentials generieren (OAuth App in Gitea + Vault + .env)
./scripts/sync-woodpecker-credentials.sh --regenerate

Was das Script macht:

  1. Liest die aktuellen Credentials aus Vault
  2. Aktualisiert die .env Datei automatisch
  3. Bei --regenerate:
  4. Löscht alte OAuth Apps in Gitea
  5. Erstellt neue OAuth App mit neuem Client ID/Secret
  6. Speichert Credentials in Vault
  7. Aktualisiert .env

Vault-Zugriff

# Vault Token (Development)
export VAULT_TOKEN=breakpilot-dev-token

# Credentials lesen
docker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \
  vault kv get secret/cicd/woodpecker

# Credentials setzen
docker exec -e VAULT_TOKEN=$VAULT_TOKEN breakpilot-pwa-vault \
  vault kv put secret/cicd/woodpecker \
  gitea_client_id="..." \
  gitea_client_secret="..."

Services neustarten nach Credentials-Änderung

# Wichtig: --force-recreate um neue Env Vars zu laden
cd /Users/benjaminadmin/Projekte/breakpilot-pwa
docker compose up -d --force-recreate woodpecker-server

# Logs prüfen
docker logs breakpilot-pwa-woodpecker-server --tail 50