ibo/infra/RUNBOOK-ibo.md
timu c54485dd6f
Some checks failed
Momentrum CI / Version (aus PR-ID / SHA) (push) Successful in 2s
Momentrum CI / Test (compile + pytest) (push) Failing after 12s
Momentrum CI / Build & Push image (push) Has been skipped
Momentrum CI / Helm lint + template (push) Successful in 8s
Momentrum CI / Deploy PROD (Image-Tag -> CD-Repo) (push) Has been skipped
ibo: Org myapps statt momentrum (Image myapps/ibo-web, CI-IMAGE)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 01:24:29 +02:00

8.1 KiB

Runbook — ibo (Immo-Bot): CI/CD, PR-Preview-dev + prod, Zitadel-SSO

Immo-Bot = Flask-Web-App + Selenium-Chrome-Sidecar (noVNC-Live-Ansicht). Umgebungs-Modell wie momentrum-kanban: ephemere PR-Previews als „dev" + eine stehende prod. Beide hinter Zitadel-SSO (die App selbst hat KEINE eigene Auth).

Umgebung Host SSO-Proxy Deploy
dev ibo-pr-<nr>.dev.momentrum.de generisches dev-sso ephemer pro PR mit Label preview (ApplicationSet)
prod ibo.momentrum.de per-App ibo-sso automatisch bei jedem main-Merge (CI → CD-Repo)

Die Muster spiegeln kanban/luxly (CI/Chart/CD/ApplicationSet) und dev-sso/ibo-sso (oauth2-proxy). Cluster-, Zitadel- und DNS-Schritte sind manuell — dieses Runbook ist die Anleitung. Reihenfolge unten einhalten.


0. Repo nach Gitea bringen

cd projekte/ibo
git add -A && git commit -m "ibo: PR-Preview-dev + prod, Zitadel-SSO"
git remote add origin momentrum-gitea:momentrum/ibo.git   # SSH-Alias wie andere Repos
git push -u origin main

Gitea-Actions-Secrets am Repo momentrum/ibo (Settings → Actions → Secrets):

  • REGISTRY_USER, REGISTRY_TOKEN — Push in die Gitea-Registry.
  • DEPLOY_TOKEN — Gitea-Token mit Write auf momentrum/momentrum-deploy (Write-back des prod-Image-Tags bei main-Merge).

1. Zitadel-Clients + Sealed-Secret

  • prod (ibo-sso) nutzt einen eigenen Zitadel-Web-Client. Dessen ClientId/ClientSecret liegen im (nicht committeten) .env des ibo-Repos und werden als SealedSecret oauth2-proxy-ibo (ns iam) in den Cluster gelegt:

    # dort ausfuehren, wo Cluster-Zugriff besteht (Tunnel localhost:16443 / Bastion):
    cd contabo-infra/platform/manifests/ibo-sso
    IBO_ENV=../../../../projekte/ibo/.env ./seal-oauth2-proxy-ibo.sh
    #   -> erzeugt sealed-oauth2-proxy-ibo.yaml  (committen & pushen -> ArgoCD entsiegelt)
    # offline-Variante (ohne Cluster) mit Public-Cert:
    #   kubeseal --controller-namespace sealed-secrets --fetch-cert > pub.pem   # einmal, mit Cluster
    #   SEALED_CERT=pub.pem IBO_ENV=.../.env ./seal-oauth2-proxy-ibo.sh
    

    Am ibo-Client in Zitadel (https://auth.momentrum.de) die Redirect-URI registrieren: https://sso.ibo.momentrum.de/oauth2/callback (Post-Logout optional: https://sso.ibo.momentrum.de).

  • dev (Previews) laufen weiter hinter dem geteilten dev-sso (Client-Secret oauth2-proxy-dev). Dessen Redirect https://sso.dev.momentrum.de/oauth2/callback existiert i. d. R. schon (kanban/luxly nutzen es) — nichts zu tun.


2. Cluster-Voraussetzungen (contabo-infra) — muessen laufen

Fuer prod (platform/manifests/ibo-sso/, ArgoCD-App platform/apps/ibo-sso.yaml):

  • oauth2-proxy ibo-sso (Deployment/Service, ns iam).
  • Middlewares iam-oauth2-ibo-auth@kubernetescrd / iam-oauth2-ibo-errors@kubernetescrd.
  • Ingress sso.ibo.momentrum.de (Login-Host, ohne Auth davor).
  • Geteilte stripPrefix-Middleware iam-strip-novnc@kubernetescrd (strip-novnc.yaml) — die Previews referenzieren sie cross-namespace (s. §4).

Fuer dev/Previews (bereits vorhanden, von kanban/luxly geteilt):

  • dev-sso (generischer oauth2-proxy *.dev.momentrum.de, Middlewares iam-oauth2-auth/iam-oauth2-errors, Login sso.dev.momentrum.de).
  • SealedSecret gitea-appset-token (ns argocd) — Gitea-Read fuer den PR-Generator.
  • AppProject previews — erlaubt Source momentrum/* (deckt ibo ab) und begrenzt Previews auf preview-*-Namespaces. Blockt bewusst traefik.io/Middleware im Preview-ns → deshalb die geteilte strip-novnc in §2.

App-of-Apps nimmt ibo-sso.yaml automatisch auf — committen & pushen genuegt; alternativ einmalig kubectl apply -f platform/manifests/ibo-sso/. Das ibo-Repo ist in platform/manifests/argocd-projects/internal.yaml (sourceRepos) bereits erlaubt (sonst lehnt ArgoCD die prod-App-Source ab).


3. DNS

A/AAAA-Records auf die Cluster-Ingress-IP:

  • ibo.momentrum.de (prod)
  • sso.ibo.momentrum.de (prod-Login)

Previews brauchen keinen eigenen Record — sie laufen unter dem bestehenden Wildcard *.dev.momentrum.de (wie kanban/luxly). cert-manager (letsencrypt-prod, HTTP-01) stellt ibo-tls, ibo-sso-tls und die per-Preview- Certs (ibo-pr-<nr>-tls) automatisch aus, sobald DNS/Ingress stehen.


4. CD-Apps im momentrum-deploy (bereits angelegt)

  • apps/internal/ibo/app.yaml — prod-Application (ibo.momentrum.de, ns apps-internal, SSO iam-oauth2-ibo-*). Auto-Sync; image.tag bumpt die CI.
  • apps/internal/ibo/preview.yaml — PR-Preview-ApplicationSet (Gitea-PR-Generator, Label-Gate preview). Rendert ibos Chart aus dem PR-Branch und setzt pro PR: Host ibo-pr-<nr>.dev.momentrum.de, priorityClassName: preview, gedeckelte Resources (preview-ns-Quota: ≤2 CPU / 1536Mi Limits gesamt), ssoMiddlewares: iam-oauth2-errors,iam-oauth2-auth (dev-sso) und novncStripPrefixRef: iam-strip-novnc@kubernetescrd (statt eigener Middleware).

committen & pushen → ArgoCD legt die prod-App + das ApplicationSet an.


5. Deploy-Flows

dev / Preview (pro PR):

  1. PR gegen main oeffnen → CI baut pr-<nr>-<sha7> (Job build-push).
  2. Am PR das Gitea-Label preview setzen (Opt-in-Gate = Concurrency-Deckel).
  3. ArgoCD-ApplicationSet (Polling 120 s) legt ibo-pr-<nr> + ns preview-ibo-pr-<nr> an → https://ibo-pr-<nr>.dev.momentrum.de.
  4. PR schliessen/mergen oder Label entfernen → Application + Namespace kaskadieren weg (finalizer + gemanagter Namespace, KEIN CreateNamespace).

prod (bei main-Merge):

  • CI-Job deploy schreibt den neuen image.tag in apps/internal/ibo/app.yaml zurueck → ArgoCD synct prod automatisch. Kein manueller Schritt.
  • Rollback: git revert des CI-Commits im momentrum-deploy (ArgoCD synct zurueck). Alternativ image.tag in app.yaml auf einen aelteren Tag setzen.

Wer prod bewusst manuell freigeben will statt Auto-Deploy: den deploy-Job in .gitea/workflows/momentrum-ci.yml entfernen und den Tag per Hand nach app.yaml committen. Aktuell ist Auto-Deploy aktiv (wie kanban).


6. Browser-Live-Ansicht (noVNC)

Der Automations-Chrome laeuft im selenium-Sidecar; sein Bild wird per noVNC gestreamt und in der Web-App eingebettet (Button „👁️ Browser live ansehen"). Routing:

  • App-Container → Chrome via SELENIUM_REMOTE_URL=http://localhost:4444.
  • Client-Browser → https://<host>/novnc/… → Ingress-Pfad /novnc → stripPrefix-Middleware → Sidecar-Port 7900 (noVNC/websockify).
    • prod: chart-eigene Middleware <ns>-ibo-novnc (App-ns).
    • Preview: geteilte iam-strip-novnc (weil das previews-Project eigene Middlewares im Preview-ns blockt).
  • Zugriff durch die SSO-Cookie (gleicher Host, gleiche Middleware-Kette).

Der Browser laeuft serverseitig im Container — es wird NICHT der lokale Browser des Nutzers ferngesteuert.


7. Break-glass (Notzugang)

Faellt Zitadel aus: die SSO-Middlewares temporaer aus ingress.ssoMiddlewares in apps/internal/ibo/app.yaml (prod) entfernen (die App selbst hat keine eigene Auth → sie ist dann OFFEN). Nur kurz, danach sofort zuruecksetzen. Nie ungeschuetzt lassen.


8. Verifikationscheckliste

  • docker compose up -d lokal → http://localhost:5000 UI, „Browser live ansehen" zeigt den Chrome im iframe (localhost:7900).
  • curl -s localhost:5000/healthz → {"ok":true}.
  • PR + Label preview → CI gruen (version→test→build-push→helm-validate), ArgoCD legt ibo-pr-<nr> an, https://ibo-pr-<nr>.dev.momentrum.de redirected zu auth.momentrum.de, nach Login landet man in der App.
  • Im Preview eingebettetes /novnc/ zeigt den Live-Browser.
  • PR schliessen → Preview + Namespace verschwinden (ArgoCD prune).
  • main-Merge → CI-Job deploy bumpt app.yaml, ArgoCD rollt prod, https://ibo.momentrum.de hinter Zitadel erreichbar.
  • Ohne SSO-Session → Login-Redirect (kein rohes 401).