diff --git a/HOMELAB_ARCHITECTURE_MASTER_V2.md b/HOMELAB_ARCHITECTURE_MASTER_V2.md index f26050f..e9d81ad 100644 --- a/HOMELAB_ARCHITECTURE_MASTER_V2.md +++ b/HOMELAB_ARCHITECTURE_MASTER_V2.md @@ -47,7 +47,7 @@ ## 2. Architektur-Prinzipien ### P1 — Traefik ist der einzige öffentliche HTTP(S)-Einstiegspunkt -Kein Webdienst veröffentlicht finale direkte Host-Ports außer `traefik` selbst. Begründete Ausnahmen: `gitea`-SSH (Port 222), `AdGuard Home` (Port 53/DNS + 8082/Admin), `Tailscale`, `Plex-Media-Server`. +Kein Webdienst veröffentlicht finale direkte Host-Ports außer `traefik` selbst. Begründete Ausnahmen: `gitea`-SSH (Port 222), `AdGuard Home` (Port 53/DNS + 8082/Admin), `Tailscale`, `Plex-Media-Server` und `influxdb3-core` Port 8181 als LAN-only Writer-Endpunkt fuer Home Assistant. ### P2 — Das Setup bleibt bewusst einfach: `frontend_net` + `backend_net` + app-interne Netze - `frontend_net` = Proxy-/Web-Netz @@ -90,6 +90,8 @@ Jeder produktive Container nutzt `restart: unless-stopped`, außer eine Ausnahme | `mealie_mealie_internal` | bridge, `internal: true` | internes Netz nur für `mealie` + `mealie-postgres` | ✅ umgesetzt | | `immich_default` | Compose-intern, `internal: true` | internes Immich-Netz | ✅ umgesetzt | | `nextcloud_internal` | bridge, `internal: true` | internes Netz nur fuer `nextcloud` + `nextcloud-postgres` + `nextcloud-redis` | ✅ vorbereitet | +| `grafana_influx_internal` | Compose-intern, `internal: true` | interne Grafana-zu-InfluxDB-Kommunikation | ✅ umgesetzt | +| `grafana_influx_lan` | Compose-intern, bridge | nicht-oeffentliches Zusatznetz nur fuer Docker Host-Port-Publishing von InfluxDB 8181 | ✅ umgesetzt | | `host` | host | nur für echte Sonderfälle | begründet | ### 3.2 Finales Diagramm (vereinfacht) @@ -118,7 +120,9 @@ dns_net App-interne Netze ├── mealie_mealie_internal (internal: true) ✅ ├── immich_default (internal: true) ✅ -└── nextcloud_internal (internal: true) ✅ +├── nextcloud_internal (internal: true) ✅ +├── grafana_influx_internal (internal: true) +└── grafana_influx_lan (Bridge fuer LAN-Port-Publishing, keine Traefik-Route) Host-Sonderfälle ├── tailscale @@ -291,7 +295,7 @@ Legende Status: | `scrutiny` | ✅ | `frontend_net` | Traefik + Middleware | aktiv via `scrutiny.kaleschke.info`, Git-Stack | `privileged` später prüfen | | `speedtest-tracker` | ✅ | `frontend_net` | Traefik + Middleware | aktiv via `speedtest.kaleschke.info` | — | | `grafana` | ✅ | `frontend_net`, `grafana_influx_internal` | Traefik + Middleware | aktiv via `grafana.kaleschke.info`, InfluxDB-Datenquelle provisioniert | Wetter-/HA-Dashboard aufbauen | -| `influxdb3-core` | ✅ | `grafana_influx_internal` + optional LAN-Bind | LAN-Port nur fuer interne Writer | InfluxDB 3 Core fuer Metriken; keine Traefik-/Public-Freigabe | HA-Write-Token und Sensor-Export finalisieren | +| `influxdb3-core` | ✅ | `grafana_influx_internal`, `grafana_influx_lan` + LAN-Bind | LAN-Port nur fuer interne Writer | InfluxDB 3 Core fuer Metriken; keine Traefik-/Public-Freigabe; Port 8181 nur via `INFLUXDB_BIND_IP` | HA-Write-Token und Sensor-Export finalisieren | ### 7.7 Noch offene Sonderfälle @@ -388,6 +392,7 @@ Für den laufenden Betrieb gilt stattdessen: | `mail-archiver` | `frontend_net` + `backend_net` | braucht Internetzugang für IMAP-Abruf (GMX, Gmail) und DB-Zugang | | `traefik/dynamic/*` | manueller Host-Sync trotz GitOps | File-Provider bleibt bewusst fuer `middlewares.yml`, `tls.yml` und `dashboards.yml`; Komodo deployed diese Dateien nicht automatisch | | `nextcloud` | keine zentrale ForwardAuth-Middleware | Nextcloud bringt eigene Auth, Clients und WebDAV/CardDAV-Endpunkte mit; Traefik bleibt Reverse Proxy, Auth bleibt app-nativ | +| `influxdb3-core` | Host-Port 8181 auf LAN-IP | Home Assistant laeuft in einer VM ausserhalb des Compose-Netzes und muss Metriken schreiben koennen; keine Traefik-Route, kein `frontend_net`, Zugriff nur ueber Token und LAN-IP `INFLUXDB_BIND_IP` | --- @@ -530,6 +535,7 @@ Mutable Tags wie `latest`, `stable`, `release` oder reine Major-Tags wurden auf - BentoPDF benoetigt fuer Office-Konvertierung die Cross-Origin-Isolation-Header `Cross-Origin-Opener-Policy: same-origin` und `Cross-Origin-Embedder-Policy: require-corp`; diese werden per Traefik-Docker-Middleware gesetzt. - `grafana` wird als geschuetztes Monitoring-UI unter `grafana.kaleschke.info` betrieben. - `influxdb3-core` bleibt ohne Traefik-/Public-Route; fuer interne Writer wie Home Assistant kann Port `8181` per `INFLUXDB_BIND_IP` auf eine LAN-Adresse gebunden werden. +- Fuer dieses Port-Publishing nutzt `influxdb3-core` zusaetzlich zum internen Grafana-Netz `grafana_influx_lan`. Das ist keine Public-App-Freigabe und ersetzt nicht die Token-Authentifizierung. - InfluxDB 3 Core nutzt einen festen Versionstag statt `latest`, weil der InfluxDB-`latest`-Tag versionsstrategisch im Umbruch ist. ### ddns-updater — Netz-Ausnahme @@ -551,4 +557,4 @@ Beispiel (Mealie): `mealie` → `frontend_net` + `mealie_mealie_internal`, `meal Dieses Dokument ist keine lose Notiz, sondern das **operative Masterdokument** für die Docker- und Zugriffsarchitektur des Homelabs. **Zielbild in einem Satz:** -`frontend_net` für Web-UIs und Dienste mit Internetbedarf, `backend_net` für interne Backends, app-interne Netze nur wenn technisch nötig, Tailscale für Remote-Admin-Zugriff, Traefik als einziger Web-Einstieg (Service-Routing via Docker-Labels, File-Provider nur für zentrale Dynamic-Config), Komodo als GitOps-Stack-Manager, AdGuard Home + Unbound für DNS, keine produktiven `bridge`-Container mehr. +`frontend_net` für Web-UIs und Dienste mit Internetbedarf, `backend_net` für interne Backends, app-interne Netze nur wenn technisch nötig, Tailscale für Remote-Admin-Zugriff, Traefik als einziger Web-Einstieg (Service-Routing via Docker-Labels, File-Provider nur für zentrale Dynamic-Config), Komodo als GitOps-Stack-Manager, AdGuard Home + Unbound für DNS, keine produktiven Container im Docker-Default-`bridge`. diff --git a/docs/GITOPS_DRIFT_RUNBOOK.md b/docs/GITOPS_DRIFT_RUNBOOK.md new file mode 100644 index 0000000..d598527 --- /dev/null +++ b/docs/GITOPS_DRIFT_RUNBOOK.md @@ -0,0 +1,127 @@ +# GitOps Drift Runbook + +Dieses Runbook ist fuer Faelle, in denen Gitea, lokaler Clone, Komodo Workspace und Docker Runtime nicht sichtbar denselben Stand haben. + +## Ziel + +Vor jeder Reparatur muss klar sein, welche Ebene vom Sollzustand abweicht: + +1. Lokaler Clone +2. Gitea `origin/master` +3. Komodo Stack Workspace auf dem Host +4. Laufender Docker-Container +5. Host-Netzwerklistener + +Nicht mehrere Ebenen gleichzeitig reparieren. Erst messen, dann genau eine Abweichung beheben. + +## Pflichtmatrix + +### 1. Lokaler Clone + +```bash +git status -sb +git rev-parse HEAD +git rev-parse origin/master +git ls-remote https://git.kaleschke.info/Micha/homelab-infra.git refs/heads/master +``` + +Alle Hashes muessen gleich sein, bevor Komodo oder Runtime bewertet werden. + +### 2. Komodo Workspace + +Auf dem Unraid-Host im Stack-Workspace: + +```bash +cd /mnt/user/services/stacks/ +git rev-parse --short HEAD +git status -sb +``` + +Bei Drift: + +```bash +git fetch --all --prune +git reset --hard origin/master +``` + +Erst danach deployen. + +### 3. Docker Runtime + +```bash +docker inspect --format '{{.Created}}' +docker inspect --format '{{json .NetworkSettings.Networks}}' +docker inspect --format '{{json .NetworkSettings.Ports}}' +docker inspect --format '{{json .HostConfig.PortBindings}}' +docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep +``` + +Wichtig: `HostConfig.PortBindings` ist nur die Container-Spezifikation. Entscheidend fuer einen aktiven Host-Port sind `NetworkSettings.Ports`, `docker ps` und ein echter Listener. + +### 4. Host-Port / Listener + +```bash +ss -ltnp | grep +curl -i --max-time 5 http://:/ +``` + +Ein `401 Unauthorized` ist bei geschuetzten APIs oft ein Erfolg: Dienst ist erreichbar, Auth fehlt nur beim Testrequest. + +## Komodo/Periphery Checks + +Wenn Komodo Stacks nicht aus Gitea deployen kann: + +```bash +docker inspect komodo-periphery --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}' +docker inspect komodo-periphery --format '{{range $k,$v := .NetworkSettings.Networks}}{{println $k}}{{end}}' +docker exec komodo-periphery sh -lc 'getent hosts git.kaleschke.info' +docker exec komodo-periphery sh -lc 'wget -S -O- -T 5 --no-check-certificate https://git.kaleschke.info 2>&1 | head -40' +``` + +Sollzustand: + +- `/mnt/user/services -> /mnt/user/services` ist gemountet. +- `komodo_net` und `frontend_net` sind verbunden. +- `git.kaleschke.info` loest auf `192.168.178.58` auf. +- HTTPS zu Gitea antwortet. + +## InfluxDB LAN-Port Beispiel + +Soll fuer Home Assistant: + +```bash +cd /mnt/user/services/stacks/grafana +git fetch --all --prune +git reset --hard origin/master +docker compose --env-file .env -p grafana -f ops/grafana-influxdb/docker-compose.yml up -d --force-recreate --no-deps influxdb3-core +``` + +Danach pruefen: + +```bash +docker network ls | grep -E "grafana|influx" +docker inspect influxdb3-core --format '{{json .NetworkSettings.Networks}}' +docker inspect influxdb3-core --format '{{json .NetworkSettings.Ports}}' +docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep influx +ss -ltnp | grep 8181 +curl -i --max-time 5 http://192.168.178.58:8181/ +``` + +Erwartung: + +- Komodo Workspace `HEAD` entspricht `origin/master`. +- `influxdb3-core` haengt an `grafana_grafana_influx_internal` und `grafana_grafana_influx_lan`. +- Docker zeigt `192.168.178.58:8181->8181/tcp`. +- `ss` zeigt `docker-proxy` auf `192.168.178.58:8181`. +- `curl` bekommt `401 Unauthorized` von InfluxDB. + +Hinweis: Im Compose-File heissen die Netze `grafana_influx_internal` und `grafana_influx_lan`. Durch den Compose-Projektnamen `grafana` werden daraus zur Laufzeit die Docker-Netze `grafana_grafana_influx_internal` und `grafana_grafana_influx_lan`. + +## Stop-Regel + +Wenn zwei Reparaturversuche nicht zum erwarteten Ergebnis fuehren: + +1. Keine weiteren Schreibbefehle. +2. Pflichtmatrix ausfuellen. +3. Genau eine abweichende Ebene benennen. +4. Erst danach einen neuen Fix ausfuehren. diff --git a/docs/MIGRATION_LOG.md b/docs/MIGRATION_LOG.md index 9ed0953..35d3091 100644 --- a/docs/MIGRATION_LOG.md +++ b/docs/MIGRATION_LOG.md @@ -16,6 +16,14 @@ Dieses Dokument ist nur noch ein historischer Verlauf. Der aktuelle operative Ab ## Historische Meilensteine +### 2026-05-04 - Home Assistant InfluxDB LAN-Port und Drift-Runbook + +- `influxdb3-core` fuer Home-Assistant-Writer auf LAN-Port `8181` vorbereitet und deployed. +- InfluxDB bleibt ohne Traefik-/Public-Route und haengt nicht im `frontend_net`. +- Fuer aktives Docker Host-Port-Publishing wurde zusaetzlich zum internen `grafana_influx_internal` das Compose-Netz `grafana_influx_lan` ergaenzt. +- Komodo Periphery dauerhaft um `/mnt/user/services:/mnt/user/services` und `frontend_net` ergaenzt, damit Stack-Workspaces und Gitea-Zugriff reproduzierbar funktionieren. +- `docs/GITOPS_DRIFT_RUNBOOK.md` angelegt, um lokale Git-Kopie, Gitea, Komodo Workspace, Docker Runtime und Host-Listener getrennt zu pruefen. + ### 2026-03-28 - GitOps-Konsolidierung - Komodo als primaeren Stack-Manager eingefuehrt. diff --git a/docs/WORKFLOW.md b/docs/WORKFLOW.md index 2252584..7033e8b 100644 --- a/docs/WORKFLOW.md +++ b/docs/WORKFLOW.md @@ -184,6 +184,22 @@ Wenn Drift erkannt wird, gilt: - 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 @@ -283,6 +299,7 @@ Nach jeder erfolgreichen Migration oder relevanten Aenderung muessen diese Datei - `docs/SECRETS_MAP.md` - `docs/ROLLBACK.md` - `HOMELAB_ARCHITECTURE_MASTER_V2.md` falls Architektur betroffen ist +- `docs/GITOPS_DRIFT_RUNBOOK.md` falls GitOps-/Komodo-/Runtime-Drift betroffen ist --- diff --git a/ops/grafana-influxdb/README.md b/ops/grafana-influxdb/README.md index e0e4059..c3c5bcc 100644 --- a/ops/grafana-influxdb/README.md +++ b/ops/grafana-influxdb/README.md @@ -8,6 +8,7 @@ Monitoring-Stack fuer Grafana + InfluxDB 3 Core. InfluxDB bleibt ohne Public Rou - InfluxDB nutzt `influxdb:3.9.1-core`, nicht `latest`, weil `latest` bei InfluxDB aktiv in Richtung InfluxDB 3 umgestellt wird. - Grafana wird ueber Traefik + `authelia@file,secure-headers@file` unter `grafana.kaleschke.info` veroeffentlicht. - InfluxDB bleibt ohne Traefik-Route. Der HTTP-Port `8181` kann fuer interne Writer wie Home Assistant ueber `INFLUXDB_BIND_IP` auf eine LAN-Adresse gebunden werden; Default ist `127.0.0.1`. +- InfluxDB haengt an zwei Compose-Netzen: `grafana_influx_internal` fuer Grafana und `grafana_influx_lan` fuer das Docker Host-Port-Publishing. Im laufenden Komodo-Stack heissen sie durch den Compose-Projektpraefix `grafana_grafana_influx_internal` und `grafana_grafana_influx_lan`. InfluxDB haengt bewusst nicht im `frontend_net`. - Grafana provisioning legt eine SQL-Datenquelle fuer InfluxDB 3 Core mit der Datenbank `homelab` an. - Der Grafana-Datasource-Token liegt als Secret-Datei auf dem Host und wird beim Containerstart nur containerintern in die fuer Grafana-Provisioning noetige Environment-Variable geladen. - Home Assistant schreibt mit der InfluxDB-v2-API-Kompatibilitaet nach InfluxDB 3; Details: `docs/HOME_ASSISTANT_INFLUXDB_ECOWITT.md`. @@ -57,6 +58,22 @@ Monitoring-Stack fuer Grafana + InfluxDB 3 Core. InfluxDB bleibt ohne Public Rou - `https://grafana.kaleschke.info` oeffnet nach Authelia die Grafana-Loginseite. - Grafana `Connections -> Data sources -> InfluxDB 3 Core -> Save & test` ist erfolgreich. - InfluxDB bleibt ohne Public Route. Falls `INFLUXDB_BIND_IP` auf die LAN-IP gesetzt ist, ist Port `8181` nur im internen Netz fuer Writer wie Home Assistant erreichbar. +- `docker ps` zeigt fuer `influxdb3-core` `192.168.178.58:8181->8181/tcp` oder den per `INFLUXDB_BIND_IP` gesetzten Host. +- `ss -ltnp | grep 8181` zeigt einen Listener auf der gebundenen Host-IP. +- `curl -i http://192.168.178.58:8181/` liefert ohne Token erwartbar `401 Unauthorized`. + +## Drift-Check + +Wenn Komodo, Gitea und Runtime nicht zusammenpassen, zuerst `docs/GITOPS_DRIFT_RUNBOOK.md` verwenden. Besonders wichtig: + +```bash +cd /mnt/user/services/stacks/grafana +git rev-parse --short HEAD +grep -nE "ports:|grafana_influx_lan|grafana_influx_internal" -A4 -B2 ops/grafana-influxdb/docker-compose.yml +docker inspect influxdb3-core --format '{{json .NetworkSettings.Ports}}' +docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep influx +ss -ltnp | grep 8181 +``` ## Rollback diff --git a/ops/grafana-influxdb/stack.env.example b/ops/grafana-influxdb/stack.env.example index 6a1aa53..af41733 100644 --- a/ops/grafana-influxdb/stack.env.example +++ b/ops/grafana-influxdb/stack.env.example @@ -1 +1,3 @@ +# Safe default: local host only. +# Set this to the Unraid LAN IP, for example 192.168.178.58, when a VM such as Home Assistant must write to InfluxDB. INFLUXDB_BIND_IP=127.0.0.1