From f2923aac62495c03de6eb0d0939e784b8e0893eb Mon Sep 17 00:00:00 2001 From: Micha Date: Sat, 30 May 2026 11:58:54 +0200 Subject: [PATCH] F-19 prep: document mem-limits baseline plan (no compose changes) ops/policy-checks/mem-limits-baseline.md captures the deliberate "not today" decision for memory limits plus the plan for when it becomes relevant: - Phase 1: 7 days of hourly docker stats snapshots - Phase 2: derive Tier-1 peak per container - Phase 3: set limits at peak * 1.5 with documented floors (Postgres 1G, Mongo 1G, Redis 256M, etc.) - Phase 4: roll out smallest-risk containers first, observe 24h between stages - Phase 5: Tier-2 only after a concrete trigger event Next trigger: family invitation out + 4 weeks stable use, or first real OOM event in docker-critical-events.sh, or a sudden Immich/Nextcloud load spike where host swap becomes visible. Today's policy check is clean (0 Critical, 1 documented Warning on influxdb3-core user 0, 13 documented Info findings on host ports / privileged exceptions / latest+digest tags). Co-Authored-By: Claude Opus 4.7 --- ops/policy-checks/mem-limits-baseline.md | 107 +++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 ops/policy-checks/mem-limits-baseline.md diff --git a/ops/policy-checks/mem-limits-baseline.md b/ops/policy-checks/mem-limits-baseline.md new file mode 100644 index 0000000..724d17f --- /dev/null +++ b/ops/policy-checks/mem-limits-baseline.md @@ -0,0 +1,107 @@ +# Memory-Limits Baseline - Vorbereitung F-19 + +Status: **Vorbereitung**. Echte `mem_limit`-Werte werden erst gesetzt, wenn mindestens 7 Tage realer Peak-Werte vorliegen. + +Bezug: `docs/AUDIT_2026-05-25.md` F-19 "Keine Container-Memory-Limits". + +## Warum nicht heute + +Audit-TODO 2026-05-30: F-19 ist nicht akut. Im `docs/MIGRATION_LOG.md` ist **kein einziger** OOM-/Memory-Vorfall dokumentiert. `services/posture-check/docker-critical-events.sh` ueberwacht `die`/`oom`/`kill`-Events und alarmiert via ntfy — der Detektions-Pfad ist da, der Daten-Befund fehlt. Limits ohne Peak-Daten zu setzen bedeutet entweder zu eng (Flapping) oder so weit weg vom Realwert, dass die Schutzwirkung gegen Null geht. + +Familien-Einladung verschiebt die Risiko-Bilanz nach oben: Ein OOM in Authelia/Postgres bei Familien-Nutzung kostet Vertrauen, nicht nur Operator-Zeit. Sobald die Einladung raus ist, wird F-19 ein "should" statt "nice". + +## Plan + +### Phase 1 - Peak-Beobachtung (7 Tage) + +Auf dem Host stuendlich `docker stats --no-stream` snappen und in eine Textfile pro Container schreiben. Beispiel-Snippet fuer das Cron-Skript: + +```bash +#!/usr/bin/env bash +# /boot/config/plugins/user.scripts/scripts/docker-stats-snapshot/script +set -euo pipefail +OUT="/mnt/user/services/policy-checks/docker-stats-$(date +%Y%m%d).log" +mkdir -p "$(dirname "$OUT")" +{ + echo "=== $(date -Iseconds) ===" + docker stats --no-stream --format 'table {{.Name}}\t{{.MemUsage}}\t{{.MemPerc}}\t{{.CPUPerc}}' +} >> "$OUT" +``` + +Cron: stuendlich (`0 * * * *`), 7 Tage laufen lassen. + +### Phase 2 - Peak-Auswertung + +Pro Tier-1-Container das Maximum `MemUsage` aus dem 7-Tage-Log ableiten: + +```bash +grep -E '^postgresql17|^authelia|^Redis|^vaultwarden|^gitea|^traefik|^komodo-mongo' \ + /mnt/user/services/policy-checks/docker-stats-*.log \ + | awk -F'\t' '{print $1, $2}' \ + | sort -u +``` + +Erwartete Groessenordnungen (zur Plausibilitaetspruefung, nicht zur Festlegung): + +| Container | Erwartung | +|---|---| +| postgresql17 | 200-600 MB | +| Redis | 30-80 MB | +| authelia | 50-150 MB | +| vaultwarden | 100-300 MB | +| gitea | 200-500 MB | +| traefik | 80-200 MB | +| komodo-mongo | 300-800 MB | + +### Phase 3 - Limit-Setting + +Pro Tier-1-Container: + +```yaml +deploy: + resources: + limits: + memory: +``` + +Floor-Werte: + +- postgresql17: 1G (Cache-Verhalten leidet bei weniger) +- komodo-mongo: 1G (WiredTiger braucht Working-Set) +- Redis: 256M (Paperless-Cache) +- vaultwarden: 256M +- gitea: 512M +- traefik: 256M +- authelia: 256M + +`mem_reservation` bewusst nicht setzen — auf einem Single-Host-Setup ist Reservation Theater. + +### Phase 4 - Rollout-Reihenfolge + +1. Redis und authelia zuerst (kleinste Risiko-Container, klares Memory-Profil). +2. Wenn nach 48 h kein Flapping: traefik, vaultwarden, gitea. +3. Zuletzt postgresql17 und komodo-mongo, weil DB-Limits bei zu engem Setting Performance kippen. + +Jede Stufe einzeln committen und 24 h beobachten. + +### Phase 5 - Tier-2 (optional) + +Tier-2 (Immich, Nextcloud, Paperless, Mealie, Mail-Archiver) bewusst spaeter, nur wenn ein konkreter Vorfall das rechtfertigt. Immich-ML ist der wahrscheinlichste Kandidat fuer den ersten echten OOM-Vorfall, deshalb dort zuerst beobachten, dann limitieren. + +## Stop-Regel + +Falls in Phase 3 ein Container nach Limit-Setzung haeufiger restartet als vor dem Limit: Limit raus, kein zweiter Versuch ohne dazwischenliegende Peak-Reanalyse. Doku-Eintrag in `docs/MIGRATION_LOG.md`, F-19 weiter offen. + +## Was nicht ins Skript gehoert + +- Mem-Limits sind kein Tuning, kein Performance-Hebel. Wer sich Performance erhofft, hat das falsche Werkzeug. +- Postgres-`shared_buffers` und `effective_cache_size` muessen zur Limit-Groesse passen. Setzen ohne Postgres-internes Tuning macht die DB langsamer, nicht stabiler. +- Komodo-Mongo waechst mit Stack-/Update-Historie. Limit fuer naechste 12 Monate planen, nicht fuer den heutigen Stand. + +## Naechster Trigger + +- Familien-Einladung raus, 4 Wochen stabile Nutzung, **oder** +- erster echter OOM-Vorfall im `docker-critical-events.sh`-Log, **oder** +- ein Immich/Nextcloud-Last-Sprung (z.B. grosses Foto-Backup), bei dem Host-Swap sichtbar wird. + +Bei einem dieser Trigger: Phase 1 starten.