Files
ROMFASTSQL/proxmox/cluster/incidents/2026-07-31-lxc110-dns-tailscale-oom.md
Claude Agent 1df533edba docs(lxc110): incident DNS/OOM 2026-07-31 + zram pe pve1 + limite TTS
LXC 110 (moltbot) a picat dupa un OOM local containerului urmat de reboot:
tailscaled a ramas delogat, iar containerul mostenea resolv.conf-ul Tailscale
de la host-ul pve1 (doar MagicDNS 100.100.100.100) -> rezolutie DNS zero desi
L3 era functional -> echo-core in crash-loop pe telegram.error.TimedOut.

Fixuri aplicate:
- pct set 110 --nameserver '10.0.20.1 1.1.1.1' (elimina dependenta de Tailscale)
- zram-tools pe pve1 (8G zstd, prio 100) - `swap: 4096` din config era fictiv,
  host-ul nu avea niciun swap; root pe ZFS deci zram, nu swapfile
- MemoryHigh/MemoryMax pe pocket-tts + supertonic-tts - toate serviciile user
  rulau cu limite `infinity`, de unde OOM-uri recurente (Apr 25, May 28 x4)
  cu victime aleatorii alese dupa oom_score_adj

Documentatie:
- nou post-mortem in cluster/incidents/, adaugat in indexuri
- README lxc110: host corectat pveelite -> pve1 (+ RAM/CPU/storage reale),
  comenzile pct redirectionate spre nodul corect
- README lxc171: tabel cu starea swap pe cele 3 noduri (pveelite are zvol,
  nu zram - nu necesita acelasi fix)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 10:14:54 +00:00

8.0 KiB

Incident 2026-07-31 — LXC 110 (moltbot): DNS mort după logout Tailscale + OOM

Severity: Medium (serviciu echo-core indisponibil ~8 min; fără pierdere de date) Detected: 2026-07-31 ~09:28 EEST (user — „nu mai răspunde la SSH, nu mai merge echo") Resolved: 2026-07-31 09:34 EEST (fix DNS) + 09:5x EEST (zram pe pve1) Author: Claude Code (mmarius28@gmail.com)


TL;DR — lanțul cauzal

  1. 06:26 UTC — LXC 110 se oprește după 65 zile uptime. În log-urile de shutdown: user-1000.slice: A process of this unit has been killed by the OOM killer. OOM local containerului (plafon 8GB), NU la nivel de host — pve1 nu a avut niciun OOM în 30 de zile și avea 18GB available.
  2. 06:26:59 — la revenire, tailscaled generează nodekey nou și rămâne delogat (machineAuthorized=false, authURL=true).
  3. DNS moare complet. LXC 110 nu avea nameserver în pct config, deci moștenea /etc/resolv.conf de la host-ul pve1 — iar acolo fișierul e scris de Tailscale și conținea doar MagicDNS (100.100.100.100 + fd7a:115c:a1e0::53). Cu Tailscale delogat, resolverul devine inaccesibil.
  4. echo-core.service intră în crash-loop cu telegram.error.TimedOut (restart counter ajunsese la 11).

Capcana de diagnostic: rețeaua L3 era perfect funcțională — ping 8.8.8.8 OK, gateway OK, rută OK. Doar rezoluția numelor pica. Ușor de interpretat greșit ca „bot stricat" sau „internet căzut".

SSH-ul „care nu răspundea" era doar containerul în curs de repornire — la verificare funcționa deja normal.


Diagnostic — comenzi cheie

# NU te lua după ping — verifică întâi rezoluția
getent hosts api.telegram.org        # gol => DNS mort
cat /etc/resolv.conf                 # doar 100.100.100.100 => depinde de Tailscale
ping -c2 8.8.8.8                     # OK => L3 e sănătos, problema e DNS
tailscale status                     # "Logged out."

# serviciile echo rulează ca user systemd (user moltbot)
su - moltbot -c 'XDG_RUNTIME_DIR=/run/user/1000 systemctl --user status echo-core'

Fix 1 — DNS explicit (aplicat)

# pe pve1
pct set 110 --nameserver '10.0.20.1 1.1.1.1'    # persistent, aplicat la următorul start

# live, fără restart de container (backup: /etc/resolv.conf.bak-2026-07-31)
printf '# --- BEGIN PVE ---\nnameserver 10.0.20.1\nnameserver 1.1.1.1\n# --- END PVE ---\n' \
  > /etc/resolv.conf

su - moltbot -c 'XDG_RUNTIME_DIR=/run/user/1000 systemctl --user restart echo-core'

Rezultat: Telegram getUpdates → 200 OK, Discord online, 0 restarturi ulterioare.

Expunere similară: orice alt LXC de pe pve1 fără nameserver explicit moștenește același resolv.conf Tailscale și va pica identic la un logout Tailscale.

Fix 2 — zram swap pe pve1 (aplicat)

pct config 110 avea swap: 4096, dar în container free -h arăta Swap: 0B. Cauza: limita cgroup exista corect pe host…

/sys/fs/cgroup/lxc/110/memory.max          = 8589934592   (8 GB)
/sys/fs/cgroup/lxc/110/memory.swap.max     = 4294967296   (4 GB)  <- plafon OK
/sys/fs/cgroup/lxc/110/memory.swap.current = 0                    <- nimic nu-l umple

…dar pve1 nu avea niciun swap (swapon --show gol, nimic în /etc/fstab). Limita cgroup e doar un plafon peste swap-ul host-ului; fără backing store fizic, kernelul nu are unde scrie paginile. Root-ul pve1 e pe ZFS (rpool/ROOT/pve-1), deci swapfile e exclus (risc de deadlock) — aceeași situație rezolvată pe pvemini în 2026-06-24.

# pe pve1 (host) — identic cu pvemini
apt install -y zram-tools
cat > /etc/default/zramswap <<'EOF'
# zram swap config - host buffer pentru spike-uri OOM (ex: LXC 110 moltbot)
ALGO=zstd
SIZE=8192
PRIORITY=100
EOF
systemctl restart zramswap.service    # enabled persistent la boot
swapon --show                         # /dev/zram0  8G  prio 100

Verificare în container — cei 4GB au acum backing real:

free -h  →  Swap: 4.0Gi

Vârfurile tranzitorii fac swap-out în loc de OOM-kill instant.


Rămas de făcut (necesită acțiune user)

Item Detalii
Re-auth Tailscale în LXC 110 Necesită login interactiv din browser (tailscale up regenerează URL-ul). Până atunci IP-ul 100.120.119.70 nu răspunde; accesul pe 10.0.20.173 e normal.
Bridge WhatsApp deconectat {"connected":false,"qr":null} pe 127.0.0.1:8098. Discord + Telegram merg. Probabil necesită re-pairing prin QR.
Monitorizare De urmărit dacă MemoryHigh pe TTS chiar oprește recurența — următorul episod ar trebui să se manifeste ca throttling, nu ca kill.

OOM-ul NU e izolat — istoric recurent

Verificarea jurnalului complet (nu doar boot-ul curent) arată că OOM-ul din 31 iulie e al cincilea episod, nu un accident:

Apr 25 08:34:53  echo-core.service: Failed with result 'oom-kill'
May 28 14:09:36  echo-core.service: Failed with result 'oom-kill'   <- 1.4G memory peak
May 28 14:15:44  echo-core.service: Failed with result 'oom-kill'
May 28 14:18:13  echo-core.service: Failed with result 'oom-kill'
May 28 14:18:13  supertonic-tts.service: Failed with result 'oom-kill'
Jul 31 06:26:22  user-1000.slice: killed by the OOM killer  -> reboot

Pe 28 mai: 4 kill-uri în 9 minute, echo-core luând cu el și supertonic-tts. Log-ul de atunci confirmă lipsa swap-ului: 1.4G memory peak, 0B memory swap peak — fără backing store, kernelul trece direct la kill.

Cauza structurală: servicii fără limite

Cele 7 servicii user systemd (echo-core, echo-taskboard, echo-whatsapp-bridge, pocket-tts, supertonic-tts, romfast-website, dbus) rulează toate fără plafon:

MemoryMax=infinity
MemoryHigh=infinity

Deci orice serviciu poate consuma singur toți cei 8 GB ai containerului, iar OOM killer-ul alege victime după oom_score_adj — de unde procesele mici ucise aiurea (dbus-daemon, sd-pam) care fac diagnosticul derutant. Stiva TTS e cea mai grea: pocket-tts ~945 MB + supertonic ~500 MB, în repaus.

Fix 3 — MemoryHigh pe stiva TTS (aplicat)

MemoryHigh face throttling + reclaim în loc de kill, deci serviciul degradează elegant sub presiune. MemoryMax e plasa de siguranță: izolează un eventual kill în interiorul serviciului, în loc să lase OOM killer-ul să aleagă victime aleatorii în tot containerul.

Drop-in-uri în ~/.config/systemd/user/<serviciu>.service.d/limits.conf (user moltbot):

Serviciu RSS repaus MemoryHigh MemoryMax
pocket-tts ~945 MB 1536M 2G
supertonic-tts ~500 MB 1024M 1536M
su - moltbot
mkdir -p ~/.config/systemd/user/pocket-tts.service.d
cat > ~/.config/systemd/user/pocket-tts.service.d/limits.conf <<'EOF'
[Service]
MemoryHigh=1536M
MemoryMax=2G
EOF
export XDG_RUNTIME_DIR=/run/user/1000
systemctl --user daemon-reload
systemctl --user restart pocket-tts supertonic-tts
systemctl --user show pocket-tts -p MemoryHigh,MemoryMax,MemoryCurrent   # verificare

Verificat post-aplicare: ambele active/running, porturile 7788 + 7789 deschise, echo-core neîntrerupt. Consum după restart: pocket-tts 773M, supertonic 463M.

Restul serviciilor (echo-core, echo-taskboard, echo-whatsapp-bridge, romfast-website) au rămas fără limite — TTS-ul e consumatorul dominant. De reevaluat dacă apar OOM-uri cu altă victimă.

Prevenție

  • zram pe pve1 amortizează spike-urile (aplicat) — dar singur e paliativ: fără limite pe servicii, swap-ul doar întârzie kill-ul. Fixul de fond e MemoryHigh pe TTS (aplicat).
  • DNS explicit pe LXC 110 elimină dependența de Tailscale (aplicat).
  • De evaluat același --nameserver pentru celelalte LXC-uri de pe pve1.
  • Alertare pe NRestarts la serviciile user systemd ar fi prins crash-loop-ul mai devreme decât raportarea manuală.

Legături: ../../lxc110-moltbot/README.md · ../../lxc171-claude-agent/README.md (secțiunea „Memorie & OOM" — incidentul zram pvemini 2026-06-24)