homelab-codex-ws/kb/audits/monitoring-coverage-2026-07-14.md
oskar ea9c6bbf7f feat(kb): przenosiny type=audit do kb/audits/ (2 pliki, bez SPLIT)
Nowy typ `audit` (rozstrzygniecie 2) — migawka stanu z pola `as_of`,
nie opis stanu biezacego.

monitoring-coverage-2026-07-14, ha-automatyzacje-2026-07-23.
Pozostale 5 audytow/reconow jest wielotypowych — wychodza w grupie SPLIT-ow.

git mv + frontmatter, tresc nietknieta.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-04 16:58:04 +02:00

490 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
okf: "0.1"
type: audit
visibility: private
status: active
updated: 2026-07-14
as_of: 2026-07-14
links: []
---
# Monitoring coverage — co biega vs co jest monitorowane (recon 2026-07-14)
**Pytanie:** czy wszystkie serwisy floty są monitorowane?
**Odpowiedź krótka:** NIE. Biega **76 kontenerów** na 5 osiągalnych węzłach, alertowanych jest **15** (~20%).
**61 kontenerów** działa bez alertowania — w tym krytyczne: vaultwarden (hasła), forgejo (git = źródło
prawdy GitOps), immich (zdjęcia), homeassistant5 (dom), obie instancje NPM (ingress), agent-system-telegram-bot
(sam kanał alertów).
---
## Metadane zbierania danych
| | |
|---|---|
| **Data zebrania** | 2026-07-14, 17:1617:17 UTC |
| **Metoda** | `docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'` |
| **PIHA** | ssh `piha` (100.108.208.3, user oskar) — 17:16:37Z |
| **VPS** | ssh `vps` (100.95.58.48, user oskar) — 17:16:39Z |
| **SOLARIA** | lokalnie (sesja biegła na solarii) — 17:16:41Z |
| **LUSTRO** | ssh `pi@100.99.85.73` (uwaga: user **pi**, nie oskar) — 17:17:11Z |
| **SATURN** | ssh `oskar@100.121.168.72` — 17:17:21Z |
| **CHELSTY-INFRA / CHELSTY-HA** | OFFLINE — `tailscale status`: last seen 42 dni temu. **Do weryfikacji po powrocie online.** |
| **Kod** | branch `task/monitoring-coverage-recon` @ parent `d5139c9` (master) |
Sekcje AC to **STAN NA DZIEŃ ZBIERANIA** (zmienny — przy odświeżaniu przewalidować w całości).
Sekcja E (klasyfikacja) i F (plan) to **DECYZJE** (trwałe — przy odświeżaniu tylko dopisać nowe kontenery).
---
## Jak działa monitoring w tym systemie (zweryfikowane w kodzie, stan na d5139c9)
Warstwy, od detekcji do alertu:
1. **node-agent** (`services/node-agent/src/node_agent.py`, `check_containers()` ~linia 305):
czyta docker socket i emituje eventy dla **WSZYSTKICH kontenerów z restart policy**
(`unless-stopped`/`always`/`on-failure`) — NIE filtruje po services.yaml.
Emituje: `containers_not_running` (exited/dead), `healthcheck_failed` (running+unhealthy),
`service_healthy` (running). Kontenery w stanie `created` pomija. **Uwaga (gap):** kontener
w stanie `restarting` (crash-loop) nie pasuje ani do `exited/dead` ani do `running`
**crash-loop nie generuje żadnego eventu** (zaobserwowane na lustro/watchtower, patrz niżej).
Nazwa kanoniczna = label `com.docker.compose.service` (fallback: nazwa kontenera).
Zdeployowany na: piha, vps, solaria, lustro (na saturnie NIE).
2. **stability-agent** (`services/stability-agent/src/stability_agent.py`): również raportuje
wszystkie kontenery (bez filtra) — eventy `containers_not_running`, `mqtt_unreachable`,
`disk_usage_high` + publikacja do Redis. Biega na piha, vps, solaria (poza services.yaml!).
3. **Observer** (`scripts/observer/observer.py`, uruchamiany w control-plane@VPS): syntetyzuje
eventy do `/opt/homelab/world/{services,nodes,incidents}.json`. Rejestruje **wszystko**
(na dziś 116 wpisów w services.json, w tym wszystkie shadow kontenery). Widoczność ≠ alert.
4. **Supervisor** (`services/control-plane/src/supervisor.py`, `reconcile()` linia 288):
generuje akcje (`redeploy`/`container_restart` → pending → Telegram → operator) **WYŁĄCZNIE
dla serwisów zadeklarowanych w `hosts/<node>/services.yaml`** (`_load_desired_state()`,
linie 161195). Flaga `monitor: false` (linie 182186) wyklucza serwis z desired-state —
serwis jest udokumentowany, ale supervisor go pomija. **To jest jedyny filtr: detekcja jest
flotowa, alertowanie tylko dla zadeklarowanych.** Dodatkowo supervisor routuje niezależnie
od desired-state: eventy `ha_*` (z ha-diag-agent), `node_offline/stale/online` (liveness
węzłów z heartbeatów node-agenta) i `disk_pressure`.
5. **fleet-prometheus** (`services/fleet-prometheus/`, VPS): scrape node_exporterów =
**liveness HOSTA, nie serwisów**. Scrape'uje: vps, piha, solaria, lustro. Świadomie NIE:
saturn (workstation, często off), chelsty (LTE, exporter DOWN — do zbadania osobno).
Alert `NodeDown` (rules/liveness.yml) tylko dla `vps|piha` (solaria/lustro bywają planowo
wyłączane). Bez Alertmanagera — alerty odbiera brain-watchdog.
6. **brain-watchdog** (`services/brain-watchdog/`, PIHA): pilnuje świeżości control-plane
(/summary) + polluje `PROMETHEUS_URL/api/v1/alerts` i forwarduje do Telegrama.
7. **ha-diag-agent** (piha → HA "ken" localhost:8123; chelsty-infra → chelsty-ha): diagnostyka
HA (websocket, integracje, encje) → supervisor routuje na alert/restart **niezależnie od
services.yaml** (dziś wisi `container-restart-piha-homeassistant` mimo braku wpisu HA
w hosts/piha/services.yaml).
**Definicja "monitorowany" w tym raporcie** = supervisor wygeneruje akcję/alert gdy serwis
padnie = wpis w `hosts/<node>/services.yaml` bez `monitor: false`, z nazwą zgodną z nazwą
compose-service kontenera.
---
## A. Stan faktyczny — pełne listy kontenerów (STAN NA 2026-07-14)
### PIHA — 42 kontenery
| Kontener | Obraz | Status | Porty |
|---|---|---|---|
| node-agent | node-agent-node-agent | Up 22h (healthy) | — |
| paperless | ghcr.io/paperless-ngx/paperless-ngx:2.14 | Up 47h (healthy) | 192.168.31.5:8210→8000 |
| vikunja | vikunja/vikunja:latest | Up 4d | 0.0.0.0:3456→3456 |
| vikunja-db | postgres:16-alpine | Up 4d (healthy) | 5432 (internal) |
| brain-watchdog | brain-watchdog-brain-watchdog | Up 4d (healthy) | — |
| paperless-db | postgres:16-alpine | Up 4d (healthy) | 192.168.31.5:5434→5432 |
| paperless-broker | redis:7-alpine | Up 4d (healthy) | 192.168.31.5:6380→6379 |
| llm-gateway | llm-gateway-llm-gateway | Up 11d (healthy) | 100.108.208.3:8080→8080 |
| kb-postgres | pgvector/pgvector:pg16 | Up 2w (healthy) | 0.0.0.0:5433→5432 |
| agent-system-webui | agent-system-webui | Up 2w | 0.0.0.0:18180→8080 |
| agent-system-runtime-materializer | agent-system-runtime-materializer | Up 2w | — |
| agent-system-telegram-bot | agent-system-telegram-bot | Up 2w | — |
| ha-diag-agent | ha-diag-agent-ha-diag-agent | Up 2w (healthy) | — |
| stability-agent | stability-agent-stability-agent | Up 2w (healthy) | — |
| agent-system-redis | redis:7 | Up 2w | 0.0.0.0:6379→6379 |
| nginxproxymanager-app-1 | jc21/nginx-proxy-manager:latest | Up 2w | 0.0.0.0:80-81→80-81, 443→443 |
| homeassistant5 | ghcr.io/home-assistant/home-assistant:stable | Up 2w | (host network, :8123) |
| immich_server | ghcr.io/immich-app/immich-server:release | Up 2w (healthy) | 0.0.0.0:2283→2283, 8081-8082 |
| immich_postgres | tensorchord/pgvecto-rs:pg14-v0.2.0 | Up 2w (healthy) | 5432 (internal) |
| immich_machine_learning | ghcr.io/immich-app/immich-machine-learning:release | Up 2w (healthy) | — |
| immich_redis | redis:6.2-alpine | Up 2w (healthy) | 6379 (internal) |
| forgejo_dind | docker:dind | Up 2w | 2375-2376 (internal) |
| forgejo | codeberg.org/forgejo/forgejo:7 | Up 12d | 0.0.0.0:3000→3000, 222→22 |
| forgejo-db-1 | postgres:14 | Up 2w | 5432 (internal) |
| zigbee2mqtt | koenkk/zigbee2mqtt | Up 3d | 0.0.0.0:8087→8080 |
| audiobookshelf | ghcr.io/advplyr/audiobookshelf:latest | Up 2w | 0.0.0.0:13378→80 |
| grafana | grafana/grafana-enterprise:latest | Up 2w | 0.0.0.0:9003→3000 |
| wikijs-db-1 | postgres:15-alpine | Up 2w | 5432 (internal) |
| code-server | lscr.io/linuxserver/code-server:latest | Up 2w | 0.0.0.0:8443→8443 |
| portainer | portainer/portainer-ce:latest | Up 2w | 0.0.0.0:8008→8000, 9009→9000 |
| prom | prom/prometheus:latest | Up 2w | 0.0.0.0:9090→9090 |
| homepage | ghcr.io/gethomepage/homepage:latest | Up 2w (healthy) | 0.0.0.0:3033→3000 |
| actual-server | actualbudget/actual-server:latest-alpine | Up 2w | 0.0.0.0:5006→5006 |
| mqtt-exporter-mqtt-exporter-1 | kpetrem/mqtt-exporter:latest | Up 2w | 0.0.0.0:9000→9000 |
| node-exporter | quay.io/prometheus/node-exporter:latest | Up 2w | — |
| wikijs-wiki-1 | ghcr.io/requarks/wiki:2 | Up 2w | 0.0.0.0:3300→3000 |
| owntracks-recorder | owntracks/recorder:latest | Up 2w | 0.0.0.0:8083→8083 |
| vaultwarden | vaultwarden/server:latest | Up 2w (healthy) | 0.0.0.0:3012→80 |
| pihole-exporter | ekofr/pihole-exporter:latest | Up 2w | 0.0.0.0:9617→9617 |
| fail2ban-prometheus-exporter-exporter-1 | registry.gitlab.com/hctrdev/fail2ban-prometheus-exporter:latest | Up 2w **(unhealthy)** | 0.0.0.0:9191→9191 |
| owntracks-prometheus-exporter-prometheus-owntracks-exporter-1 | linusgroh/prometheus-owntracks-exporter | Up 2w | 0.0.0.0:8780→80 |
| own-tracks-frontend-owntracks-frontend-1 | owntracks/frontend | Up 2w | 0.0.0.0:8084→80 |
Zmiany vs audyt 2026-06-30 (`docs/infra/inventory-2026-06-30.md`): **przybyły** paperless,
paperless-db, paperless-broker (Deploy 1, 2026-07-10); **zniknęły** diskover i elasticsearch
(w audycie 06-30 były w 33 shadow; dziś nie biegają). 06-30: 40 kontenerów → dziś: 42.
### VPS — 24 kontenery
| Kontener | Obraz | Status | Porty |
|---|---|---|---|
| control-plane-executor | control-plane-executor | Up 46m (healthy) | — |
| control-plane-observer | control-plane-observer | Up 46m (healthy) | — |
| control-plane-supervisor | control-plane-supervisor | Up 46m (healthy) | — |
| control-plane-ui | control-plane-operator-ui | Up 46m (healthy) | 0.0.0.0:18180→8080 |
| fleet-prometheus | prom/prometheus:v3.5.0 | Up 2w (healthy) | 100.95.58.48:9090→9090 |
| node-agent | node-agent-node-agent | Up 2w (healthy) | — |
| humanai-mailer | humanai-mailer | Up 2w | — |
| humanai-landing | humanai-landing | Up 2w | 80 (internal) |
| umami | ghcr.io/umami-software/umami:postgresql-latest | Up 2w (healthy) | 3000 (internal) |
| umami-db | postgres:16-alpine | Up 2w (healthy) | 5432 (internal) |
| node_exporter | quay.io/prometheus/node-exporter:latest | Up 5w | (host network :9100) |
| stability-agent | stability-agent-stability-agent | Up 5w (healthy) | — |
| outline-outline-1 | outlinewiki/outline:1.6.1 | Up 5w (healthy) | 0.0.0.0:3000→3000 |
| outline-postgres-1 | 4e6e670bb069 (anonimowy image ID!) | Up 5w (healthy) | 5432 (internal) |
| outline-redis-1 | redis:7-alpine | Up 5w (healthy) | 6379 (internal) |
| ai-cluster-service-ops-worker-1 | ai-cluster-service-ops-worker | Up 5w | — |
| ai-cluster-codex-worker-1 | ai-cluster-codex-worker | Up 5w | — |
| ai-cluster-openclaw-1 | ai-cluster-openclaw | Up 5w (healthy) | 0.0.0.0:8000→8000 |
| ai-cluster-planner-worker-1 | ai-cluster-planner-worker | Up 5w | — |
| ai-cluster-redis-1 | redis:7-alpine | Up 5w | 6379 (internal) |
| mosquitto | eclipse-mosquitto:2 | Up 5w | 100.95.58.48:1883→1883 |
| joplin-server | joplin/server:latest | Up 5w | 127.0.0.1:22300→22300 |
| npm | jc21/nginx-proxy-manager:latest | Up 5w | 0.0.0.0:80-81→80-81, 443→443 |
| joplin-db | postgres:18 (pre-release tag!) | Up 5w (healthy) | 5432 (internal) |
**gokapi NIE biega** mimo deklaracji w hosts/vps/services.yaml — supervisor poprawnie to wykrył:
w `/opt/homelab/actions/pending/` wisi `redeploy-vps-gokapi.json`. To dowód, że monitoring
desired-state DZIAŁA dla zadeklarowanych serwisów.
### SOLARIA — 5 kontenerów
| Kontener | Obraz | Status | Porty |
|---|---|---|---|
| paperless-worker | ghcr.io/paperless-ngx/paperless-ngx:2.14 | Up 5h (healthy) | 8000 (internal) |
| planner-agent | planner-agent-planner-agent | Up 5h (healthy) | — |
| node-agent | node-agent-node-agent | Up 5h (healthy) | — |
| stability-agent | stability-agent-stability-agent | Up 5h (healthy) | — |
| node_exporter | quay.io/prometheus/node-exporter:latest | Up 5h | (host network :9100) |
### LUSTRO — 4 kontenery
| Kontener | Obraz | Status | Porty |
|---|---|---|---|
| node-agent | node-agent-node-agent | Up 20h (healthy) | — |
| node-exporter | quay.io/prometheus/node-exporter:latest | Up 20h | (host network :9100) |
| piper-tts | piper-tts-rpi5 | Up 20h | 0.0.0.0:5000→5000, 10200→10200 |
| pi-watchtower-1 | containrrr/watchtower | **Restarting (1) — crash-loop!** | — |
**pi-watchtower-1 jest w crash-loopie** i przez lukę w node-agencie (stan `restarting` nie
generuje eventu, patrz sekcja o mechanizmie) — **nikt tego nie widzi**; world-state pokazuje
`lustro/watchtower healthy` (stary event `service_healthy`).
### SATURN — 1 kontener
| Kontener | Obraz | Status | Porty |
|---|---|---|---|
| agent-system-webui | agent-system-webui | Up 9h | 0.0.0.0:8080→8080 |
Stack control-plane z audytu 06-30 (executor/observer/supervisor/ui) już NIE biega na saturnie
— posprzątane. Saturn nie ma node-agenta, nie ma services.yaml, nie jest scrape'owany przez
fleet-prometheus → **węzeł całkowicie poza monitoringiem** (świadomie: workstation, często off).
### CHELSTY-INFRA / CHELSTY-HA — OFFLINE (42 dni)
Niedostępne przez Tailscale (last seen ~2026-06-02). Deklaracje: chelsty-infra = ha-diag-agent,
node-agent, mosquitto, zigbee2mqtt, frigate; chelsty-ha = homeassistant (`monitor: false`).
`world/services.json` nadal pokazuje serwisy chelsty-infra jako "healthy" — to STĘCHŁY stan
(status serwisów nie wygasa; liveness wygasa tylko na poziomie węzła). **Do weryfikacji po
powrocie online**, w tym: czy alerty `node_offline` dla chelsty odpaliły 42 dni temu.
---
## B. Stan deklarowany — hosts/<node>/services.yaml (STAN NA 2026-07-14)
| Węzeł | Zadeklarowane serwisy | monitor: false? |
|---|---|---|
| piha | ha-diag-agent, node-agent, brain-watchdog, vikunja, llm-gateway, kb-postgres | — |
| vps | node-agent, control-plane, node_exporter, fleet-prometheus, gokapi | — |
| solaria | node-agent | — |
| lustro | node-agent | — |
| saturn | **BRAK PLIKU services.yaml** | — |
| chelsty-infra | ha-diag-agent, node-agent, mosquitto, zigbee2mqtt, frigate | — |
| chelsty-ha | homeassistant | **TAK** (node-agent tam nie zdeployowany; HA kryty pośrednio przez MQTT) |
Razem: **18 deklaracji alertowalnych** (w tym 5 na offline'owym chelsty-infra) + 1 z monitor:false.
Uwaga: `stability-agent` ma katalogi w `hosts/{piha,solaria,vps}/runtime/`, ale NIE ma wpisów
w żadnym services.yaml — sam strażnik nie jest pilnowany.
---
## C. Luka — biega, ale poza alertowaniem (STAN NA 2026-07-14)
Pokrycie per węzeł (kontenery alertowane / biegające):
| Węzeł | Biega | Alertowane | Luka |
|---|---|---|---|
| PIHA | 42 | 6 (node-agent, ha-diag-agent, brain-watchdog, vikunja, llm-gateway, kb-postgres) | **36** |
| VPS | 24 | 7 (node-agent, control-plane ×4¹, node_exporter, fleet-prometheus) | **17** |
| SOLARIA | 5 | 1 (node-agent) | **4** |
| LUSTRO | 4 | 1 (node-agent) | **3** |
| SATURN | 1 | 0 | **1** |
| **RAZEM** | **76** | **15** | **61 (~80%)** |
¹ control-plane to 1 deklaracja pokrywająca 4 kontenery — node-agent na VPS probe'uje endpoint
HTTP :18180/summary i emituje `service_healthy`/`service_unhealthy` dla logicznego serwisu
"control-plane" (`_check_control_plane_health()`).
Częściowe pokrycie (nie liczone jako "alertowane" powyżej):
- **homeassistant5@piha** — ha-diag-agent pilnuje websocketu HA i supervisor generuje
`container_restart`/`alert_only` niezależnie od services.yaml. Padnięcie HA zostanie
zauważone. Brak jednak wpisu desired-state (drift "kontener zniknął" nie będzie wykryty).
- **node-exporter@piha** — jego padnięcie = `up==0` w fleet-prometheus = alert NodeDown
(piha) przez brain-watchdog → Telegram. Pośrednio alertowany.
- **node_exporter@solaria, node-exporter@lustro** — scrape'owane, ale świadomie wyłączone
z reguły NodeDown (węzły planowo wyłączane) → brak alertu.
- **gokapi@vps** — zadeklarowany, NIE biega; drift poprawnie wykryty (pending
`redeploy-vps-gokapi.json`). Luka deploymentu, nie monitoringu.
---
## D. Nowe serwisy KB — weryfikacja wpisu z backlogu (f135365)
Backlog ("Nowe serwisy KB nie sa w monitoringu", 2026-07-12) **potwierdzony w połowie**
paperless i paperless-worker faktycznie poza monitoringiem; gokapi/llm-gateway/kb-postgres są OK:
| Serwis | services/<name>/ w repo? | hosts/*/services.yaml? | Biega? | Alertowany? |
|---|---|---|---|---|
| paperless (+db, +broker) | ✓ (+ hosts/piha/runtime/paperless) | ✗ | ✓ piha (healthy) | **✗ LUKA** |
| paperless-worker | ✓ (owner_node: solaria) | ✗ | ✓ solaria (healthy) | **✗ LUKA** |
| nextcloud | ✓ (owner_node: piha, commit 7e5577c) | ✗ | ✗ nigdzie (nie zdeployowany) | ✗ (nie dotyczy — dodać wpis RAZEM z deployem) |
| gokapi | ✓ (owner_node: vps) | ✓ hosts/vps | **✗ nie biega** | ✓ — drift wykryty, wisi `redeploy-vps-gokapi` |
| llm-gateway | ✓ (owner_node: piha) | ✓ hosts/piha | ✓ piha (healthy) | ✓ |
| kb-postgres | ✓ (owner_node: piha) | ✓ hosts/piha | ✓ piha (healthy) | ✓ |
---
## E. Klasyfikacja niemonitorowanych kontenerów (DECYZJA — trwała)
Kategorie:
- **A (pełny GitOps):** krytyczny — docelowo compose w `services/`, service.yaml, deploy przez
deploy.sh. Każde A dostaje NAJPIERW wpis monitoringowy (krok B) — tanio, od razu.
- **B (tylko monitoring):** deployment zostaje jak jest; dodać do `hosts/<node>/services.yaml`
→ supervisor alarmuje gdy padnie.
- **C (świadomie poza):** padnięcie nie boli / narzędzie jednorazowe. Uzasadnienie obowiązkowe.
Kontenery pomocnicze stacka (db/redis/broker) dziedziczą kategorię stacka — w services.yaml
deklaruje się serwis główny (padnięcie db zwykle wywala healthcheck głównego kontenera).
### PIHA (36 luk)
| Kontener | Co robi | Kategoria | Uzasadnienie |
|---|---|---|---|
| vaultwarden | menedżer haseł | **A** (najpierw B) | Hasła całej rodziny — padnięcie/utrata danych boli maksymalnie; musi być w GitOps z backupem i alertem |
| forgejo, forgejo-db-1, forgejo_dind | git hosting + CI | **A** (najpierw B) | Źródło prawdy GitOps + OIDC dla vikunji; bez forgejo nie ma deployów; już zidentyfikowane w audycie 06-30 (owner_node błędnie=saturn) |
| homeassistant5 | Home Assistant "ken" (dom) | **A** (najpierw B) | Automatyka domu; częściowo kryty przez ha-diag-agent (websocket), ale bez wpisu desired-state; wpis `homeassistant` w services.yaml domknie lukę |
| immich_server, immich_postgres, immich_machine_learning, immich_redis | zdjęcia rodzinne | **A** (najpierw B) | Dane niereprodukowalne (zdjęcia); padnięcie = brak backupu telefonów w tle, zauważalne późno |
| nginxproxymanager-app-1 | ingress LAN (*.kapala.org: HA, immich, paperless, cloud…) | **A** (najpierw B) | Pojedynczy punkt wejścia do wszystkich usług domowych; padnięcie = "wszystko nie działa" |
| paperless, paperless-db, paperless-broker | KB: dokumenty (OCR pipeline) | **B** | Już w GitOps (services/paperless + runtime override) — brakuje TYLKO wpisu w services.yaml; przypadek z backlogu f135365 |
| stability-agent | watchdog węzła | **B** | Repo-managed (runtime override jest); strażnik musi być pilnowany; dotyczy też vps i solarii |
| zigbee2mqtt | bridge Zigbee→MQTT (ken) | **B** | services/zigbee2mqtt istnieje (owner=piha); sensory domowe przestają raportować gdy padnie |
| agent-system-telegram-bot | kanał alertów Telegram | **B** | Jak padnie, ŻADEN alert nie dojdzie — a nikt się nie dowie; pilnować w pierwszej kolejności |
| agent-system-webui | operator UI (approve akcji) | **B** | Bez niego nie da się zatwierdzać akcji z przeglądarki; część pętli human-in-the-loop |
| agent-system-redis | redis dla agent-system | **B** | Zależność telegram-bota i webui; tani wpis |
| agent-system-runtime-materializer | materializacja runtime agentów | **B** | Część stacka agent-system; padnięcie cichaczem psuje odświeżanie stanu |
| wikijs-wiki-1, wikijs-db-1 | wiki | **B** | Notatki/dokumentacja domowa — padnięcie boli umiarkowanie, wpis jest tani |
| actual-server | budżet domowy | **B** | Dane finansowe; używany regularnie, padnięcie zauważalne przy wpisywaniu wydatków |
| prom | domowy Prometheus (LAN) | **B** | Źródło metryk domowych (HA, piha OS); padnięcie = dziura w historii; UWAGA: ma plaintext token HAOS (anti-pattern, patrz services/fleet-prometheus/prometheus.yml komentarz) |
| owntracks-recorder | lokalizacja rodziny (backend) | **C** | Hobby/eksperyment; padnięcie = luka w śladzie lokalizacji, nie boli operacyjnie |
| own-tracks-frontend-… | frontend owntracks | **C** | Czysta wizualizacja |
| owntracks-prometheus-exporter-… | exporter owntracks | **C** | Pomocniczy; objaw padnięcia = brak metryk, widoczny w grafanie |
| mqtt-exporter-mqtt-exporter-1 | exporter MQTT→prom | **C** | Jak wyżej |
| pihole-exporter | exporter pihole | **C** | Jak wyżej |
| fail2ban-prometheus-exporter-… | exporter fail2ban | **C** | Jak wyżej; DZIŚ unhealthy — naprawić lub usunąć (follow-up) |
| node-exporter | metryki hosta dla fleet-prometheus | **C** | Pośrednio alertowany: padnięcie = up==0 = NodeDown(piha) przez brain-watchdog |
| grafana | dashboardy | **C** | Wizualizacja; padnięcie zauważalne przy wejściu, zero utraty danych (provisioning/db na dysku) |
| homepage | strona startowa | **C** | Kosmetyka |
| audiobookshelf | audiobooki | **C** | Media; restart ręczny wystarczy |
| code-server | IDE w przeglądarce | **C** | Narzędzie dev, używane ad-hoc |
| portainer | GUI dockera | **C** | Narzędzie administracyjne ad-hoc; wręcz kandydat do usunięcia (GitOps ma być źródłem prawdy) |
### VPS (17 luk)
| Kontener | Co robi | Kategoria | Uzasadnienie |
|---|---|---|---|
| npm | publiczny ingress okit.pl | **A** (najpierw B) | Cała publiczna powierzchnia (share.okit.pl, vikunja.okit.pl…); manifesty A już istnieją na NIEZMERGOWANEJ gałęzi `feat/vps-service-migration` (commit 862c04a, cutover niewykonany) |
| mosquitto | broker MQTT ai-cluster | **B** | services/mosquitto istnieje ale owner_node=piha (błąd — biega na VPS od tygodni, audyt 06-30 poz. 3); szyna komunikacji ai-cluster |
| stability-agent | watchdog węzła | **B** | Jak na piha |
| outline-outline-1, outline-postgres-1, outline-redis-1 | wiki zespołowa | **B** | Notatki; manifesty na gałęzi feat/vps-service-migration; przy okazji naprawić anonimowy image ID postgresa (audyt 06-30 poz. 19) |
| joplin-server, joplin-db | sync notatek | **B** | Notatki osobiste; przy okazji zejść z postgres:18 pre-release (audyt 06-30 poz. 20) |
| ai-cluster-codex-worker-1, ai-cluster-planner-worker-1, ai-cluster-service-ops-worker-1, ai-cluster-openclaw-1, ai-cluster-redis-1 | workery agentowe | **B** | Padnięcie = agenci przestają mielić kolejki (objawia się późno); docelowo migracja compute na SOLARIA (CLAUDE.md), monitoring dodać już teraz |
| humanai-landing, humanai-mailer | strona publiczna + mailer | **B** | Publiczna wizytówka — padnięcie boli reputacyjnie i cicho (nikt nie patrzy); brak w repo (audyt 06-30 poz. 21) |
| umami, umami-db | analityka www | **C** | Statystyki odwiedzin; padnięcie = luka w danych analitycznych, nie boli operacyjnie |
### SOLARIA (4 luki)
| Kontener | Co robi | Kategoria | Uzasadnienie |
|---|---|---|---|
| paperless-worker | OCR/konsument kolejki KB | **B** | Przypadek wprost z backlogu f135365: "jesli worker padnie (…) dowiesz sie po tym, ze kolejka nie jest przetwarzana"; repo+runtime są, brakuje wpisu |
| planner-agent | agent planowania | **B** | services/planner-agent istnieje (owner=solaria ✓); audyt 06-30 poz. 14 |
| stability-agent | watchdog węzła | **B** | Jak na piha/vps |
| node_exporter | metryki hosta | **C** | Scrape'owany, ale solaria świadomie poza NodeDown (planowe wyłączenia); alerting wróci z anomaly-detection (backlog) |
### LUSTRO (3 luki)
| Kontener | Co robi | Kategoria | Uzasadnienie |
|---|---|---|---|
| piper-tts | TTS dla magic mirror | **C** | Padnięcie = lustro nie mówi; kosmetyka. Jeśli tani wpis — można podnieść do B przy okazji |
| node-exporter | metryki hosta | **C** | Jak solaria — świadomie poza NodeDown |
| pi-watchtower-1 | auto-update obrazów | **C** + **follow-up PILNY** | DZIŚ w crash-loopie, niewykrywalnym przez node-agent (luka na stan `restarting`). Decyzja operatora: naprawić albo USUNĄĆ (watchtower na edge = niekontrolowane pulle, sprzeczne z GitOps) |
### SATURN (1 luka)
| Kontener | Co robi | Kategoria | Uzasadnienie |
|---|---|---|---|
| agent-system-webui | operator UI (kopia dev?) | **C** | Saturn = workstation, często wyłączony; świadomie poza monitoringiem (jak w fleet-prometheus). Wyjaśnić czemu biega duplikat UI z pihy (follow-up) |
---
## F. Plan domknięcia — paczki na jedną sesję każda (DECYZJA — trwała)
**Zasada procesowa (z backlogu, do utrwalenia):** wpis w `hosts/<node>/services.yaml` +
`inventory/topology.yaml` to CZĘŚĆ deployu każdego nowego serwisu, nie osobny krok "kiedyś".
**⚠ Gotcha techniczna dla WSZYSTKICH paczek (sprawdzić przed każdym wpisem):** supervisor
matchuje klucz `node/nazwa-serwisu` z nazwą kanoniczną kontenera = label
`com.docker.compose.service` (node_agent.py `_canonical_container_name()`). Dla stacków
compose'owych to NIE jest nazwa kontenera: np. `nginxproxymanager-app-1` ma compose-service
**"app"**, `wikijs-wiki-1` → "wiki", stąd w world/services.json wiszą kolizyjne klucze typu
`piha/app`, `piha/db`, `piha/redis`, `piha/database`. Przed dodaniem wpisu sprawdzić na hoście:
`docker inspect <kontener> --format '{{ index .Config.Labels "com.docker.compose.service" }}'`
— i jeśli label koliduje/jest ogólnikowy, najpierw nadać `container_name` + porządny compose
project name albo poprawić observer (patrz follow-upy). Bez tego wpis będzie wiecznym
`missing_service` i zaspamuje kolejkę akcji.
### Paczka 1 — KB + już-zGitOps'owane serwisy (najtańsza-najważniejsza; czysta kategoria B)
Serwisy, które JUŻ są w repo (services/ + runtime overrides) — brakuje tylko rejestracji:
1. `hosts/piha/services.yaml`: + paperless, + stability-agent, + zigbee2mqtt
2. `hosts/solaria/services.yaml`: + paperless-worker, + planner-agent, + stability-agent
3. `hosts/vps/services.yaml`: + stability-agent, + npm, + mosquitto (i naprawić
`services/mosquitto/service.yaml` owner_node: piha→vps oraz `services/npm` — potwierdzić
że nazwa compose-service = "npm")
4. `inventory/topology.yaml`: dopisać ww. do sekcji węzłów
5. Weryfikacja: po 12 cyklach supervisora `world/services.json` ma klucze o zgodnych nazwach,
kolejka pending NIE zawiera fałszywych `missing_service`; test driftu: `docker stop
paperless-worker` na chwilę → pojawia się akcja → `docker start` → akcja auto-cancelled
(test wymaga zgody operatora; alternatywnie tylko obserwacja biernie)
6. Domknięcie wiszącego driftu: zdeployować gokapi na VPS (akcja `redeploy-vps-gokapi` już
czeka na approve) — UWAGA: brak `hosts/vps/runtime/gokapi/docker-compose.override.yml`
z mem_limit (reguła VPS 4GB) — dodać przed deployem.
### Paczka 2 — krytyczne shadow na PIHA (kategoria B dla przyszłych A)
Wpisy monitoringowe (bez ruszania deploymentu!) dla: vaultwarden, forgejo, homeassistant
(kontener homeassistant5), immich, nginxproxymanager (compose-service prawdopodobnie "app" —
patrz gotcha!), agent-system (telegram-bot, webui, redis, runtime-materializer), wikijs,
actual-server, prom. Każdy wpis poprzedzony sprawdzeniem compose-label na hoście.
Jeśli labels kolidują (db/app/redis) — najpierw follow-up "canonical naming" (niżej) albo
wpis odroczony z adnotacją.
### Paczka 3 — VPS shadow (kategoria B + przygotowanie cutover)
1. Wpisy: outline, joplin, ai-cluster, humanai-landing, humanai-mailer (+ umami jeśli tanio)
2. Przejrzeć gałąź `feat/vps-service-migration` (commit 862c04a: manifesty npm/outline/joplin/
ai-cluster; cutover NIE wykonany) — zdecydować: merge + cutover per checklista z CLAUDE.md,
czy przepisać od nowa. UWAGA: CLAUDE.md już dziś twierdzi "All VPS services are now
GitOps-managed" — to NIEPRAWDA na masterze; poprawić doc albo zmergować gałąź.
### Paczka 4 — pełny GitOps dla krytycznych (kategoria A; JEDEN serwis = JEDNA sesja)
Kolejność wg bólu: 1) vaultwarden, 2) forgejo, 3) npm@piha + npm@vps (cutover), 4) immich,
5) homeassistant5. Dla każdego: compose do `services/<name>/`, service.yaml, env.example,
healthcheck.sh, runtime override w `hosts/piha/runtime/`, deploy przez deploy.sh.
**Reguła migracji danych: ścieżki danych zostają NA MIEJSCU** (CLAUDE.md) — zero przenoszenia
wolumenów bez osobnego planu.
### Paczka 5 — porządki i decyzje C (follow-upy)
- **lustro/pi-watchtower-1**: naprawić albo usunąć (crash-loop TERAZ; watchtower vs GitOps)
- **piha/fail2ban-exporter**: unhealthy od ≥2 tyg. — naprawić albo usunąć
- **saturn/agent-system-webui**: wyjaśnić czemu biega; usunąć jeśli pozostałość dev
- **nextcloud**: przy deployu (osobna sesja per plan KB) wpis do services.yaml OD RAZU
- **chelsty**: po powrocie online powtórzyć inwentaryzację (sekcja "Jak odświeżyć")
- **saturn**: decyzja czy dostaje node-agenta + services.yaml (dziś świadomie poza)
### Follow-upy techniczne w kodzie monitoringu (poza zakresem tego reconu, do osobnych tasków)
1. **node-agent nie widzi stanu `restarting`** (crash-loop = cisza) — dodać gałąź dla
`status == "restarting"` w `check_containers()` → event `containers_not_running` lub nowy
typ `container_crash_loop`. Dowód: lustro/pi-watchtower-1.
2. **Kolizje nazw kanonicznych** w observerze/node-agencie: label `com.docker.compose.service`
bez project-name daje klucze `piha/db`, `piha/app`, `piha/redis` (dziś w world/services.json
są duplikaty typu `piha/immich_server` I `piha/immich-server`). Propozycja: klucz
`<project>_<service>` albo preferować container_name gdy label jest ogólnikowy.
3. **Stęchły world-state dla offline węzłów**: serwisy chelsty-infra "healthy" 42 dni po
zniknięciu węzła — status serwisu powinien degradować się razem z liveness węzła.
4. **Alerting solaria/lustro**: świadomie wyłączone z NodeDown; docelowo anomaly detection
(istniejący backlog "Plan: Monitoring floty — Prometheus jako źródło prawdy").
---
## TL;DR
- **Biega:** 76 kontenerów (42 piha, 24 vps, 5 solaria, 4 lustro, 1 saturn); chelsty-infra/ha
offline od ~42 dni — niezweryfikowane.
- **Alertowane:** 15 kontenerów przez 13 deklaracji desired-state (+ HA częściowo przez
ha-diag-agent, + node-exporter@piha pośrednio przez NodeDown, + gokapi: zadeklarowany,
niezdeployowany, drift POPRAWNIE wykryty i wisi w pending).
- **Luka:** 61 kontenerów (~80%) bez alertowania. Detekcja (node-agent/observer) widzi
wszystko; filtr jest w supervisorze — alertuje TYLKO to, co wpisane w
`hosts/<node>/services.yaml` (bez `monitor: false`).
- **Najboleśniejsze luki:** vaultwarden (hasła), forgejo (git), immich (zdjęcia),
homeassistant5 (dom, częściowo kryty), npm ×2 (cały ingress), agent-system-telegram-bot
(kanał alertów pilnujący wszystkiego innego, sam niepilnowany).
- **Znaleziska przy okazji:** lustro/watchtower w crash-loopie niewykrywalnym przez node-agent
(luka na stan `restarting`); fail2ban-exporter@piha unhealthy; gokapi czeka na deploy;
CLAUDE.md błędnie twierdzi że VPS jest w pełni GitOps (manifesty na niezmergowanej gałęzi).
- **Co najpierw:** Paczka 1 (wpisy dla paperless, paperless-worker, stability-agent ×3,
zigbee2mqtt, npm, mosquitto, planner-agent — wszystko już w repo, tylko rejestracja)
→ Paczka 2 (krytyczne shadow PIHA) → Paczka 3 (VPS) → Paczka 4 (pełny GitOps po kolei).
---
## Jak odświeżyć ten dokument
1. Stan faktyczny (sekcja A) — jedna pętla (uwaga na userów ssh: lustro=pi, reszta=oskar;
solaria/saturn wg tego skąd odpalasz):
```bash
for target in oskar@100.108.208.3 oskar@100.95.58.48 oskar@100.100.231.104 \
pi@100.99.85.73 oskar@100.121.168.72 oskar@100.98.91.98; do
echo "===== $target ====="
ssh -o ConnectTimeout=10 -o BatchMode=yes "$target" \
"date -u +%Y-%m-%dT%H:%M:%SZ; docker ps --format '{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'"
done
```
(kolejno: piha, vps, solaria, lustro, saturn, chelsty-infra; chelsty-infra pomiń jeśli offline)
2. Stan deklarowany (sekcja B): `grep -A2 "^services:" hosts/*/services.yaml` + ręcznie
sprawdzić flagi `monitor: false`.
3. Luka (sekcja C): porównać 1 z 2 per węzeł; pamiętać że 1 deklaracja może pokrywać stack
wielokontenerowy (control-plane, vikunja) i że match idzie po labelu
`com.docker.compose.service`, nie po nazwie kontenera.
4. Wiszące akcje/drifty: `ssh vps ls /opt/homelab/actions/pending/`.
5. Sekcje EF: NIE odtwarzać — tylko dopisać nowe kontenery i odhaczyć wykonane paczki.
Zmienić klasyfikację wolno tylko świadomą decyzją (to sekcje DECYZYJNE).