# Workflow - GitOps / No-Drift Regeln Dieses Dokument definiert den verbindlichen Arbeitsablauf fuer Aenderungen an der Homelab-Infrastruktur. --- ## Ziel Es darf **keine dauerhafte Abweichung** zwischen: - Gitea Online - lokalem Clone - Komodo-Stacks - laufenden Docker-Containern - Host-Konfiguration geben. **Grundsatz:** > Gitea Online ist die operative Quelle der Wahrheit. --- ## Betriebsmodell Die Rollen sind bewusst getrennt: - **Gitea Online** ist `origin` und damit der verbindliche Sollzustand. - Der **lokale Clone** ist die Arbeitskopie fuer Aenderungen. - **Komodo** deployed aus Gitea und ist kein Bearbeitungsort. - Der **Host** ist Laufzeit, nicht Quelle der Wahrheit. ### Operative Hierarchie 1. `origin/master` in Gitea 2. lokaler Clone auf dem Windows-PC 3. Komodo-Deployments / Webhooks 4. laufende Container und Host-Dateien Wenn diese Ebenen voneinander abweichen, gewinnt immer zuerst Git und nicht der manuelle Live-Zustand. --- ## Standard-Workflow Aenderungen werden immer in dieser Reihenfolge durchgefuehrt: 1. Lokal synchronisieren 2. Lokal aendern 3. Commit erzeugen 4. Push nach Gitea 5. Komodo reagiert automatisch per Webhook 6. Ergebnis testen 7. Doku pruefen und nachziehen --- ## Standardwerkzeug fuer den Alltag Der bevorzugte lokale Workflow ist: - **GitHub Desktop** fuer `Fetch`, `Pull`, `Commit`, `Push` - Editor nach Wahl fuer Datei-Aenderungen - Gitea Web fuer Historie, Review und kleine Notfaelle - Komodo nur fuer Deploy-Status, Logs und Stack-Sicht ### Tagesablauf mit GitHub Desktop Vor lokaler Arbeit: 1. GitHub Desktop oeffnen 2. `Fetch origin` 3. wenn noetig `Pull origin` Nach lokaler Arbeit: 1. Aenderungen pruefen 2. bei Compose-/Backup-/Restore-Aenderungen relevante manuelle Repo-Checks ausfuehren - `ops/policy-checks/check_repo.ps1` - `ops/restore-tests/check-restore-freshness.ps1` oder gezielte Restore-Checks 2. Commit mit sauberer Nachricht 3. `Push origin` 4. Komodo-Webhook im Hinterkopf behalten --- ## Wenn online in Gitea gearbeitet wurde Web-Aenderungen in Gitea sind erlaubt, aber nicht der Normalfall. Wenn online etwas geaendert wurde, gilt **vor der naechsten lokalen Arbeit**: 1. GitHub Desktop oeffnen 2. `Fetch origin` 3. `Pull origin` 4. erst dann lokal weiterarbeiten Sonst entsteht Drift zwischen Gitea Online und lokalem Clone. --- ## Komodo-Regeln Komodo ist in diesem Setup: - primaeres Deployment-Werkzeug - GitOps-Consumer fuer die Stacks - Monitoring- und Status-Werkzeug ### Deshalb gilt - Stack-Konfiguration nur im Repository anpassen - nicht im Komodo-Web-Editor arbeiten - Pushes koennen automatisch einen Komodo-Deploy ausloesen - wenn Komodo und Git voneinander abweichen, gewinnt Git ### Pflicht bei neuen Komodo-Stacks Jeder neue produktive Komodo-Stack, der aus `Micha/homelab-infra` deployed wird, braucht einen aktiven Gitea-Webhook auf die aktuelle Komodo-Stack-ID. Pflichtschritte beim Anlegen: 1. Stack in Komodo aus Gitea anlegen 2. `webhook_enabled` in Komodo aktivieren 3. passenden Gitea-Webhook fuer die aktuelle Stack-ID anlegen 4. Gitea-Hook gegen `http://komodo-core:9120/listener/github/stack//deploy` pruefen 5. einen Push oder Test-Delivery ausloesen und `last_status`/Komodo-Deploy pruefen 6. Ausnahmen explizit dokumentieren **Regel:** Kein neuer produktiver GitOps-Stack ohne funktionierenden Gitea->Komodo-Webhook. Bewusste Ausnahmen muessen im selben Aenderungsblock dokumentiert werden, inklusive Grund und Alternativ-Deploy-Weg. Der Standardfall nutzt den globalen `KOMODO_WEBHOOK_SECRET` aus der Komodo-Host-`.env`, ausser Komodo zeigt fuer den Stack explizit ein eigenes per-Stack-Secret. ### Ausnahme: Komodo-Zugangsmodell Komodo bleibt **bewusst** ohne zentrale Traefik-ForwardAuth-Middleware. Grund: - Komodo hat eigene Authentifizierung - Komodo nutzt REST- und WebSocket-Endpunkte - Webhooks laufen ueber `/listener/...` - Periphery nutzt den speziellen WebSocket-Pfad `/ws/periphery` Deshalb wird Komodo aktuell nur ueber Traefik veroeffentlicht, aber **nicht** pauschal mit `authelia@file` vorgeschaltet. **Regel:** Aenderungen an Komodo-Auth, Komodo-Routing oder vorgeschalteter Middleware nur nach expliziter Wirkungspruefung auf: - UI-Login - Gitea-Webhooks - Periphery-Verbindung - API-/Automationszugriffe --- ## Verbotene Arbeitsweise Folgende Dinge sind grundsaetzlich zu vermeiden: - Aenderungen direkt im Komodo-Web-Editor - Aenderungen direkt per `docker run` - Aenderungen an laufenden Containern ohne Repo-Anpassung - spontane Host-Hotfixes ohne Nachdokumentation - Secrets im Git-Repository - mehrere kritische Dienste gleichzeitig migrieren --- ## Erlaubte Arbeitsweise Erlaubt und gewuenscht sind: - Aenderungen an Compose-Dateien im Git-Repo - Commit + Push vor jedem produktiven Deploy - GitHub Desktop als Standardweg fuer den lokalen Sync - Gitea Web fuer Review, Historie und kleine Hotfixes - Host-Hotfixes nur im Ausnahmefall mit sofortiger Nachpflege im Repo --- ## No-Drift-Prinzip ### Definition **Configuration Drift** liegt vor, wenn der reale Zustand vom Git-Zustand abweicht. Beispiele: - laufender Container wurde manuell veraendert - lokaler Clone ist nicht mehr auf dem Stand von `origin/master` - Komodo-Stack entspricht nicht mehr dem Repo - Host-Dateien wurden angepasst, aber nicht dokumentiert - Traefik dynamic config wurde lokal geaendert, aber Git weiss nichts davon ### Regel Wenn Drift erkannt wird, gilt: 1. Drift **nicht ignorieren** 2. Drift **sofort benennen** 3. entscheiden: - Repo an Realitaet anpassen - oder Realitaet an Repo zurueckfuehren 4. erst danach weiterarbeiten ### Pflichtcheck bei Drift-Verdacht Vor jedem Reparaturversuch muessen die Ebenen getrennt geprueft werden: 1. lokaler Clone 2. Gitea `origin/master` 3. Komodo Stack Workspace 4. Docker Runtime 5. Host-Netzwerklistener Das detaillierte Runbook steht in `docs/GITOPS_DRIFT_RUNBOOK.md`. **Regel:** `HostConfig.PortBindings` allein beweist keinen aktiven Host-Port. Entscheidend sind `NetworkSettings.Ports`, `docker ps`, `ss -ltnp` und ein echter `curl` gegen den Host-Port. **Stop-Regel:** Wenn zwei Reparaturversuche nicht zum erwarteten Ergebnis fuehren, keine weiteren Schreibbefehle ausfuehren. Erst die Pflichtmatrix aus dem Runbook ausfuellen. --- ## Ausnahmefall: Hotfix auf dem Host Manchmal ist ein Live-Hotfix noetig. Das ist erlaubt, aber nur unter diesen Bedingungen: 1. Hotfix nur wenn der Dienst sonst nicht funktioniert 2. Aenderung sofort dokumentieren 3. Aenderung danach ins Git-Modell ueberfuehren 4. kein stiller Dauerzustand ### Pflicht bei Hotfixes - Was wurde geaendert? - Wo wurde es geaendert? - Warum war es noetig? - Muss diese Aenderung ins Repo uebernommen werden? - Ist ein Rollback dokumentiert? --- ## Ausnahme: Traefik Dynamic Config > **Diese Dateien werden von Komodo nicht automatisch deployed.** Komodo deployed ausschliesslich `docker-compose.yml`-Dateien. Die Traefik-Konfigurationsdateien unter `traefik/dynamic/` im Git-Repo werden **nicht** automatisch auf den Host uebertragen. Diese Ausnahme bleibt bewusst bestehen. Der File-Provider wird weiterhin nur fuer zentrale Middlewares, TLS und Dashboard-Konfiguration genutzt, waehrend Service-Routing ueber Docker-Labels laeuft. ### Betroffene Dateien | Git-Pfad | Host-Pfad (NAS) | |---|---| | `traefik/dynamic/middlewares.yml` | `/mnt/user/appdata/traefik/dynamic/middlewares.yml` | | `traefik/dynamic/tls.yml` | `/mnt/user/appdata/traefik/dynamic/tls.yml` | | `traefik/dynamic/dashboards.yml` | `/mnt/user/appdata/traefik/dynamic/dashboards.yml` | ### Pflicht-Workflow bei Aenderungen an Traefik Dynamic Config 1. Datei im Git-Repo (`traefik/dynamic/`) aendern 2. Commit + Push 3. Datei manuell auf den Host kopieren 4. Traefik laedt dynamic config automatisch neu 5. Aenderung testen > **Merksatz:** Git-Commit allein reicht hier nicht. Ohne den manuellen Kopier-Schritt wirkt die Aenderung nicht. --- ## Ausnahme: Authelia configuration.yml > **Diese Datei wird von Komodo nicht automatisch deployed.** `security/authelia/configuration.yml` ist die Repo-Baseline fuer nicht geheime Einstellungen (Access-Control, Session, Storage-Struktur, Notifier, TOTP). Die produktive Host-Datei darf zusaetzlich OIDC-Clients und hostseitige Identity-Provider-Konfiguration enthalten. Secret-Werte und die User-Datenbank bleiben grundsaetzlich ausserhalb von Git. | Git-Pfad | Host-Pfad (NAS) | |---|---| | `security/authelia/configuration.yml` | `/mnt/user/appdata/authelia/config/configuration.yml` | ### Pflicht-Workflow bei Aenderungen an `configuration.yml` 1. Datei im Git-Repo (`security/authelia/`) aendern. 2. Commit + Push. 3. Aenderung manuell in die Host-Datei mergen, OIDC-/Identity-Provider-Sektionen erhalten. 4. `docker restart authelia` und Login-Smoke-Test auf einer ACL-betroffenen Domain. 5. `services/authelia-diff.sh` (Default-Aufruf) muss `exit 0` liefern. ### Automatische Drift-Erkennung `services/authelia-diff.sh` vergleicht die `access_control:`-Sektion zwischen Repo-Baseline und Host-Datei. Der Posture-Check (`services/posture-check/posture-check.sh`) ruft das Skript als Check `authelia_config_drift` auf und meldet Drift als Warning via ntfy. Konfigurierbare Variablen (Defaults sind das produktive Zielbild): - `AUTHELIA_REPO_BASELINE` — Pfad zur Repo-Datei auf dem Host, Default `/mnt/user/services/homelab-infra/security/authelia/configuration.yml` - `AUTHELIA_HOST_CONFIG` — Pfad zur produktiven Host-Datei, Default `/mnt/user/appdata/authelia/config/configuration.yml` - `AUTHELIA_DIFF_SECTIONS` — Komma-Liste der zu vergleichenden Top-Level-Sektionen, Default `access_control` - `AUTHELIA_DIFF_SCRIPT` — Pfad zum Diff-Skript fuer den Posture-Check, Default `/mnt/user/services/homelab-infra/services/authelia-diff.sh` - `SKIP_AUTHELIA_DRIFT=1` — Check im Posture-Check ueberspringen Pflicht-Setup auf dem Host: Repo-Spiegel unter `/mnt/user/services/homelab-infra/` (Read-only-Clone von Gitea `Micha/homelab-infra`, regelmaessig `git pull --ff-only`). Ohne Repo-Spiegel meldet der Check Warning, weil die Baseline-Datei fehlt — Critical wird der Check bewusst nicht. > **Merksatz:** Push allein reicht hier nicht. Ohne den manuellen Merge ins Host-Configfile wirkt die Aenderung nicht, und der Drift-Check wuerde Warning melden. --- ## Secrets-Regeln - Secrets liegen niemals im Repository - Secrets liegen unter `/mnt/user/appdata/secrets/` - Secrets werden ueber Datei-Mounts mit `_FILE` Variablen oder Komodo Stack Environment Variables eingebunden - Rechte: `chmod 600` - Secret-Namen und Pfade werden in `docs/SECRETS_MAP.md` dokumentiert --- ## Image-Versionierung - Mutable Tags wie `latest`, `stable`, `release` oder reine Major-Tags werden nach Moeglichkeit auf den **aktuell laufenden Digest** gepinnt. - Digest-Pinning friert den bekannten Laufzeitstand ein; es ist **kein** automatisches Upgrade. - Echte Versions-Upgrades sind ein eigener, bewusster Aenderungsblock mit anschliessendem Test. - Wenn der laufende Digest unbekannt ist, wird er zuerst am produktiven Container ausgelesen und erst danach im Repo festgeschrieben. --- ## DNS-Regeln fuer Container Nicht alle Container koennen externe DNS-Namen aufloesen. Standardmaessig nutzt Docker `127.0.0.11` als internen DNS-Resolver. In bestimmten Netzwerk-Setups schlaegt externe Namensaufloesung damit fehl (`server misbehaving`). ### Regel Container die **externe Domains aufloesen muessen** erhalten explizit: ```yaml dns: - 1.1.1.1 - 8.8.8.8 ``` ### Aktuell betroffen | Service | Grund | |---|---| | `traefik` | ACME Let's Encrypt (`acme-v02.api.letsencrypt.org`) | | `ddns-updater` | IP-Erkennung (ipify.org) + Cloudflare API | --- ## Service-Removal-Checkliste Wenn ein Stack endgueltig entfernt wird (Beispiele: Homepage am 2026-05-25, Uptime-Kuma am 2026-05-25, Jellyfin am 2026-05-25), muss in **einem** Aenderungsblock auch der gesamte Sicht-/Backup-Pfad nachgezogen werden, sonst entstehen "Tote-Pfad-Warnings", die erst Tage spaeter auftauchen. Pflicht-Schritte vor dem Schliessen: 1. Komodo: Stack stoppen, destroy, Stack-Eintrag loeschen. 2. Gitea-Webhook fuer den Stack deaktivieren. 3. Repo-Pfad per `git rm` entfernen. 4. Appdata nach `/mnt/user/appdata/_archive/-removed-YYYY-MM-DD/` verschieben (14 Tage Karenz). 5. DNS-Eintrag im Cloudflare entfernen, sofern Public-Domain. 6. Authelia ACL-Eintrag in `security/authelia/configuration.yml` und auf dem Host bereinigen. 7. Monitoring: Blackbox-Target in `monitoring/blackbox/blackbox.yml` entfernen, Cert-Check-Liste pruefen. 8. **Borg-UI Source-Liste**: `https://borg.kaleschke.info` -> Repository `appdata-critical` -> Source Directories -> alle `/local/appdata/` und ggf. `/local/`-Eintraege loeschen. Sonst kommen daily `HomelabBorgLastJobCompletedWithWarnings`-Push-Nachrichten mit `BackupFileNotFoundError` im Logfile. 9. `docs/SERVICE_CATALOG.md`, `docs/REPO_MAP.md` und `HOMELAB_ARCHITECTURE_MASTER_V2.md` Sektion 7.8 (Entfernt) nachziehen. Wenn ein Stack `webhook_enabled` in Komodo hatte, zusaetzlich pruefen, ob der zugehoerige Gitea-Hook deaktiviert oder geloescht wurde. --- ## Dokumentationspflicht Nach jeder erfolgreichen Migration oder relevanten Aenderung muessen diese Dateien geprueft werden: - `docs/SECRETS_MAP.md` - `docs/ROLLBACK.md` - `docs/SERVICES_RECOVERY.md` falls `/mnt/user/services`, Gitea, Komodo oder Host-Automation betroffen sind - `docs/HARDWARE_INVENTORY.md` und `docs/CAPACITY_AND_LIFECYCLE.md` falls Hardware, Disks, Cache, RAM oder USV betroffen sind - `docs/NETWORK_INVENTORY.md` und `docs/EXTERNAL_DEPENDENCIES.md` falls Router, DNS, Tailscale, Portfreigaben oder Provider betroffen sind - `HOMELAB_ARCHITECTURE_MASTER_V2.md` falls Architektur betroffen ist - `docs/GITOPS_DRIFT_RUNBOOK.md` falls GitOps-/Komodo-/Runtime-Drift betroffen ist --- ## Rollback-Regel Jede Aenderung muss rueckrollbar sein. Vor jedem Deploy muss klar sein: - wie der letzte funktionierende Zustand aussieht - welcher Commit der letzte stabile Stand ist - ob Datenpfade unveraendert bleiben - wie der Dienst im Fehlerfall zurueckgenommen wird Wenn Rollback nicht klar ist, wird nicht deployed. --- ## Arbeitsregel fuer KI-Assistenten Wenn mit einer KI gearbeitet wird, gilt immer: > Lies zuerst: > 1. `HOMELAB_ARCHITECTURE_MASTER_V2.md` > 2. `docs/WORKFLOW.md` > 3. die betroffene Compose-Datei > 4. die relevante Betriebsdoku aus `docs/README.md` Erst danach duerfen Aenderungen vorgeschlagen werden. --- ## Merksatz > Erst syncen, dann aendern. > Erst Git, dann Deploy. > Kein Drift, kein Chaos.