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"
Go Services (consent-service, ai-compliance-sdk)¶
# 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:
- Liest die aktuellen Credentials aus Vault
- Aktualisiert die .env Datei automatisch
- Bei
--regenerate: - Löscht alte OAuth Apps in Gitea
- Erstellt neue OAuth App mit neuem Client ID/Secret
- Speichert Credentials in Vault
- 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="..."