Infrastruktur¶
Kamerplanter läuft auf Kubernetes und kann alternativ mit Docker Compose betrieben werden. Für die Entwicklung ist Skaffold mit einem lokalen Kind-Cluster der primäre Workflow. Dieses Dokument beschreibt alle Betriebsvarianten und die CI/CD-Pipeline.
Deployment-Varianten im Überblick¶
graph TB
subgraph "Produktion / Staging"
K8S["Kubernetes 1.28+\n(beliebiger Anbieter)"]
HELM["Helm Chart\nhelm/kamerplanter/"]
end
subgraph "Lokale Instanz"
DC["Docker Compose\ndocker-compose.yml"]
end
subgraph "Entwicklung"
SKAFFOLD["Skaffold + Kind"]
KIND["Kind-Cluster\nkind-config.yaml"]
end
HELM --> K8S
SKAFFOLD --> KIND Kubernetes (Produktion)¶
Helm-Chart¶
Der Helm-Chart liegt unter helm/kamerplanter/ und basiert auf der bjw-s common library. Diese Library vereinheitlicht Deployment-Definitionen und vermeidet Boilerplate.
helm/kamerplanter/
├── Chart.yaml
├── Chart.lock
├── values.yaml # Produktions-Defaults
├── values-dev.yaml # Entwicklungs-Overrides (Skaffold)
├── charts/ # Abhängigkeiten (bjw-s common, ArangoDB, Valkey)
└── templates/ # Helm-Templates (Ingress, ConfigMaps, ...)
Container-Images¶
| Komponente | Image |
|---|---|
| Backend | ghcr.io/nolte/kamerplanter-backend:latest |
| Frontend | ghcr.io/nolte/kamerplanter-frontend:latest |
Images werden über GitHub Actions gebaut und in der GitHub Container Registry (ghcr.io) veröffentlicht.
Kubernetes-Ressourcen¶
Pro Komponente werden deployt:
Backend (FastAPI) - Deployment mit 2 Replicas, RollingUpdate (1 Surge, 0 Unavailable) - Liveness-Probe: GET /api/v1/health/live - Readiness-Probe: GET /api/v1/health/ready - Ressourcen: 250m CPU / 256Mi Memory (Request), 1 CPU / 512Mi (Limit)
Frontend (nginx) - Deployment mit 2 Replicas, RollingUpdate - Liveness-Probe: GET / - Ressourcen: 50m CPU / 64Mi Memory (Request), 200m / 128Mi (Limit)
ArangoDB - StatefulSet mit PersistentVolumeClaim für Datenpersistenz - Port 8529
Valkey - StatefulSet mit PersistentVolumeClaim (1Gi in Dev) - Port 6379
Celery Worker + Beat - Je ein Deployment ohne Replika-Skalierung (Worker: 1, Beat: 1) - Gleiche Image wie Backend, anderer Startbefehl (celery ... worker bzw. celery ... beat)
Ingress (Traefik)¶
Traefik übernimmt TLS-Terminierung und Routing:
https://kamerplanter.example.com → Frontend (Port 80)
https://kamerplanter.example.com/api/ → Backend (Port 8000)
TLS-Zertifikate werden via cert-manager oder manuell bereitgestellt.
Health-Endpunkte¶
| Endpunkt | Zweck |
|---|---|
GET /api/v1/health/live | Liveness: Backend-Prozess läuft |
GET /api/v1/health/ready | Readiness: ArangoDB verbunden, Daten geladen |
GET /api/health | Root-Level-Health für M2M-Clients (Home Assistant) |
Docker Compose (einfacher Start)¶
Für schnelle Evaluierungen und lokale Einzelinstallationen ohne Kubernetes. Alle 6 Dienste in einer Datei:
# Dienste in docker-compose.yml
arangodb # Port 8529
valkey # Port 6379
backend # Port 8000 (FastAPI, KAMERPLANTER_MODE=light)
celery-worker # Hintergrundaufgaben
celery-beat # Zeitgesteuerte Aufgaben
frontend # Port 8080 (nginx)
Schnellstart¶
cp .env.example .env # Passwörter setzen
docker-compose up -d # Alle Dienste starten
# Frontend erreichbar unter http://localhost:8080
Credentials werden aus .env gelesen — keine hartcodierten Passwörter in der docker-compose.yml.
Skaffold + Kind (Entwicklung)¶
Voraussetzungen¶
- Skaffold >= v2
- Kind (Kubernetes in Docker)
- Docker oder Podman
- Node.js 25.1.0 (asdf
.tool-versionsim Frontend-Verzeichnis)
Cluster erstellen¶
Entwicklungsworkflow¶
# Alle Komponenten starten (Backend + Frontend)
skaffold dev
# Nur Backend
skaffold dev --profile=backend-only
# Nur Frontend
skaffold dev --profile=frontend-only
# Debug-Modus (debugpy aktiviert)
skaffold debug
Skaffold übernimmt: 1. Docker-Images lokal bauen (Dockerfile.dev) 2. Images in den Kind-Cluster laden (kein Push zu einer Registry nötig) 3. Helm-Chart deployen (helm/kamerplanter/values-dev.yaml) 4. Datei-Sync: Geänderte .py-, .ts- und .tsx-Dateien werden direkt in die laufenden Container kopiert — kein komplettes Rebuild nötig
Port-Forwarding¶
Skaffold richtet folgende Port-Forwardings ein:
| Dienst | Cluster-Port | Lokaler Port |
|---|---|---|
| Backend | 8000 | 8000 |
| Frontend | 5173 | 3000 |
| ArangoDB | 8529 | 8529 |
| Home Assistant | 8123 | 8123 |
Skaffold-Profile¶
| Profil | Verwendung |
|---|---|
| (default) | Backend + Frontend |
backend-only | Nur Backend, kein Frontend-Image-Build |
frontend-only | Nur Frontend, kein Backend-Image-Build |
debug | Backend mit debugpy (Remote-Debugging Port 5678) |
Skaffold ist der einzige Entwicklungsworkflow
Kein manuelles docker build, docker push oder kubectl apply. Skaffold übernimmt alles. Direktes kubectl-Patching von Deployments wird beim nächsten skaffold dev-Lauf überschrieben.
Home-Assistant-Integration¶
Die HA-Custom-Component liegt unter src/ha-integration/custom_components/kamerplanter/. Sie wird nicht automatisch per Skaffold deployt, da sie in den HA-Pod kopiert werden muss:
# 1. Dateien in den Pod kopieren
kubectl cp src/ha-integration/custom_components/kamerplanter/ \
default/homeassistant-0:/config/custom_components/kamerplanter/
# 2. Python-Cache löschen (wichtig! sonst lädt HA alten Bytecode)
kubectl exec -n default homeassistant-0 -- \
rm -rf /config/custom_components/kamerplanter/__pycache__
# 3. Pod neustarten (PVC bleibt erhalten)
kubectl delete pod homeassistant-0 -n default
CI/CD (GitHub Actions)¶
Workflows¶
.github/workflows/
├── docs.yml # Dokumentation bauen und deployen
├── backend.yml # pytest, ruff, Docker-Image-Build
└── frontend.yml # vitest, ESLint, Docker-Image-Build
Backend-Pipeline¶
graph LR
PR["Pull Request"] --> LINT["ruff check + format"]
LINT --> TEST["pytest\n821 Tests"]
TEST --> BUILD["Docker Build\n(ghcr.io)"]
BUILD -->|"main branch"| PUSH["Image Push\nghcr.io/nolte/kamerplanter-backend"] Frontend-Pipeline¶
graph LR
PR["Pull Request"] --> ESLINT["ESLint\n+ TypeScript Check"]
ESLINT --> TEST["vitest\n198 Tests"]
TEST --> BUILD["Docker Build\n(ghcr.io)"]
BUILD -->|"main branch"| PUSH["Image Push\nghcr.io/nolte/kamerplanter-frontend"] Dokumentations-Pipeline¶
graph LR
PUSH["Push auf main\n(docs/** geändert)"] --> BUILD["mkdocs build --strict"]
BUILD --> CHECK["Link-Check"]
CHECK --> DEPLOY["mike deploy\n(GitHub Pages)"] Umgebungsvariablen¶
Alle Konfiguration erfolgt über Umgebungsvariablen. Die wichtigsten:
| Variable | Standard | Beschreibung |
|---|---|---|
ARANGODB_HOST | localhost | ArangoDB-Hostname |
ARANGODB_PORT | 8529 | ArangoDB-Port |
ARANGODB_DATABASE | kamerplanter | Datenbankname |
REDIS_URL | redis://localhost:6379/0 | Valkey/Redis-URL |
KAMERPLANTER_MODE | full | full oder light |
JWT_SECRET_KEY | (kein Default!) | JWT-Signing-Key — in Produktion setzen! |
CORS_ORIGINS | ["http://localhost:3000"] | Erlaubte CORS-Origins (JSON-Array) |
DEBUG | false | Debug-Modus (kein HSTS, farbige Logs) |
REQUIRE_EMAIL_VERIFICATION | false | E-Mail-Verifizierung erzwingen |
PERENUAL_API_KEY | "" | API-Key für Perenual-Stammdatenanreicherung |
JWT_SECRET_KEY in Produktion setzen
Der Default-Wert change-me-in-production-use-openssl-rand-hex-32 darf in Produktionsumgebungen niemals verwendet werden. Einen sicheren Key generieren:
Renovate (Dependency-Updates)¶
Dependency-Updates werden automatisch via Renovate als Pull Requests erstellt. Die Konfiguration liegt in renovate.json5.