docs(lxc171): add reap-orphans cron + zram swap anti-OOM
Incident 2026-06-24: OOM-uri repetate în cgroup /lxc/171 cauzate de swap nebacked pe host (pvemini fără swap) + acumulare de forks vscode-server orfane și sesiuni logind zombie. - scripts/reap-orphans.sh: reaping conservator (forks ~/.vscode-server orfane >24h + sesiuni closing cu leader mort), rulat din cron la 6h - README: secțiune Memorie & OOM (zram pe host ZFS, reaper, diagnostic), corectat date stale host/RAM/CPU (pvemini, 16GB, 4 cores) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
**Director:** `proxmox/lxc171-claude-agent/`
|
||||
**VMID:** 171
|
||||
**IP:** 10.0.20.171 (intern) | 100.95.55.51 (Tailscale)
|
||||
**Host Proxmox:** pveelite (10.0.20.202)
|
||||
**Host Proxmox:** pvemini (10.0.20.201)
|
||||
**Rol:** Mediu de dezvoltare izolat pentru Claude Code
|
||||
|
||||
---
|
||||
@@ -16,6 +16,7 @@
|
||||
| `scripts/work.sh` | Meniu interactiv pentru workflow complet |
|
||||
| `scripts/new-task.sh` | Creează branch nou pentru task |
|
||||
| `scripts/finish-task.sh` | Finalizează task (commit + push) |
|
||||
| `scripts/reap-orphans.sh` | Curăță procese vscode-server orfane + sesiuni zombie (cron, anti-OOM) |
|
||||
|
||||
---
|
||||
|
||||
@@ -27,11 +28,11 @@
|
||||
| Hostname | claude-agent |
|
||||
| IP intern | 10.0.20.171 |
|
||||
| IP Tailscale | 100.95.55.51 |
|
||||
| Host Proxmox | pveelite (10.0.20.202) |
|
||||
| Host Proxmox | pvemini (10.0.20.201) |
|
||||
| User | claude |
|
||||
| Storage | local-zfs (32GB) |
|
||||
| RAM | 4GB |
|
||||
| CPU | 2 cores |
|
||||
| RAM | 16GB (swap 8GB — vezi nota OOM mai jos) |
|
||||
| CPU | 4 cores |
|
||||
|
||||
## Componente Instalate
|
||||
|
||||
@@ -176,6 +177,84 @@ git push -u origin feature/nume-feature
|
||||
# Creează Pull Request în Gitea
|
||||
```
|
||||
|
||||
## Memorie & OOM (reaping orfane + zram)
|
||||
|
||||
### Context (incident 2026-06-24)
|
||||
|
||||
Containerul a generat OOM-uri repetate, izolate în cgroup-ul `/lxc/171` (NU la nivel de
|
||||
host — host-ul avea memorie liberă). Cauzele combinate:
|
||||
|
||||
1. **Swap fictiv:** LXC 171 are `memory: 16384` + `swap: 8192`, dar host-ul **pvemini nu
|
||||
avea swap deloc** → swap-ul containerului nu era backed de nimic. La atingerea celor
|
||||
16GB se intra direct în OOM-kill, fără să poată face swap-out. Victimele tipice erau
|
||||
procese mici cu `oom_score_adj` ridicat (`systemd`, `dbus-daemon`, `at-spi-bus-laun`,
|
||||
`sd-pam`) din sesiunile `user@1000`.
|
||||
2. **Acumulare de fond:** forks `~/.vscode-server` (servere VS Code Remote-SSH) rămase
|
||||
orfane după ce conexiunea SSH moare — reparentate la init (PPID=1), vechi de zile — plus
|
||||
sesiuni `systemd-logind` blocate în stare `closing`. Un spike ocazional de
|
||||
Chromium/Playwright împingea totalul peste 16GB → OOM.
|
||||
|
||||
### Fix 1 — zram swap pe host (pvemini)
|
||||
|
||||
Root-ul pvemini e pe **ZFS**, deci **NU** se folosește swapfile (risc de deadlock). În loc,
|
||||
zram (swap comprimat în RAM):
|
||||
|
||||
```bash
|
||||
# pe pvemini (host)
|
||||
apt install -y zram-tools
|
||||
cat > /etc/default/zramswap <<'EOF'
|
||||
ALGO=zstd
|
||||
SIZE=8192
|
||||
PRIORITY=100
|
||||
EOF
|
||||
systemctl restart zramswap.service # enabled persistent la boot
|
||||
zramctl; swapon --show # verificare: /dev/zram0 8G zstd
|
||||
```
|
||||
|
||||
Acum cei 8GB `swap` din configul LXC 171 au backing real → vârfurile tranzitorii fac
|
||||
swap-out în loc de OOM-kill instant.
|
||||
|
||||
### Fix 2 — reaping orfane (`scripts/reap-orphans.sh`, cron în 171)
|
||||
|
||||
Script conservator care rulează ca root **în interiorul containerului**, la fiecare 6 ore:
|
||||
|
||||
- omoară forks `~/.vscode-server` reparentate la init (PPID=1) **și** mai vechi de 24h
|
||||
(conexiune SSH moartă);
|
||||
- termină sesiunile `logind` în stare `closing` cu leader mort (`leader=0`).
|
||||
|
||||
Exclude explicit daemonul de bază `/usr/lib/code-server` (lansat de ttyd) și procesele
|
||||
Claude Code (pot fi task-uri lungi legitime). Log în `/var/log/reap-orphans.log`.
|
||||
|
||||
```bash
|
||||
# instalare în container (din host)
|
||||
pct push 171 reap-orphans.sh /usr/local/sbin/reap-orphans.sh # sau deploy manual
|
||||
pct exec 171 -- chmod +x /usr/local/sbin/reap-orphans.sh
|
||||
# cron: /etc/cron.d/reap-orphans -> 0 */6 * * * root /usr/local/sbin/reap-orphans.sh
|
||||
|
||||
# rulare manuală + verificare
|
||||
pct exec 171 -- /usr/local/sbin/reap-orphans.sh
|
||||
pct exec 171 -- tail /var/log/reap-orphans.log
|
||||
```
|
||||
|
||||
> ⚠️ **NU** folosi `loginctl terminate-session` pe sesiuni `closing` care au `leader != 0` —
|
||||
> acelea pot fi sesiuni VS Code remote active de lucru. Doar zombiile cu `leader=0` sunt
|
||||
> sigure (asta verifică și scriptul automat).
|
||||
|
||||
### Diagnostic rapid OOM
|
||||
|
||||
```bash
|
||||
# pe host: confirmă că OOM e în cgroup-ul containerului, nu pe host
|
||||
ssh root@10.0.20.201 "journalctl -k --since '1 hour ago' | grep -iE 'oom_memcg|Killed process'"
|
||||
cat /sys/fs/cgroup/lxc/171/memory.events # oom / oom_kill counters
|
||||
cat /sys/fs/cgroup/lxc/171/memory.current # consum curent vs memory.max (16G)
|
||||
|
||||
# în container: top consumatori + orfani + sesiuni
|
||||
pct exec 171 -- bash -c "ps -eo pid,ppid,etimes,rss,comm --sort=-rss | head -20"
|
||||
pct exec 171 -- loginctl list-sessions
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Claude Code nu pornește
|
||||
@@ -367,4 +446,4 @@ ssh claude@<ip> "chmod +x /workspace/*.sh && ln -sf /workspace/start-agent.sh ~/
|
||||
---
|
||||
|
||||
**Data setup:** 2025-12-31
|
||||
**Ultima actualizare:** 2026-01-27
|
||||
**Ultima actualizare:** 2026-06-24 (zram swap pvemini + reap-orphans cron, anti-OOM)
|
||||
|
||||
52
proxmox/lxc171-claude-agent/scripts/reap-orphans.sh
Executable file
52
proxmox/lxc171-claude-agent/scripts/reap-orphans.sh
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# reap-orphans.sh — curăță procese VS Code Remote-SSH orfane + sesiuni logind zombie.
|
||||
#
|
||||
# Context: LXC 171 (claude-agent) acumulează forks ~/.vscode-server reparentate la init
|
||||
# (conexiunea SSH a murit, dar serverul Remote-SSH rămâne) + sesiuni logind blocate în
|
||||
# stare 'closing'. Acestea umplu treptat cgroup-ul de 16GB; împreună cu spike-uri
|
||||
# Chromium/Playwright declanșau OOM-kill în /lxc/171 (incident 2026-06-24).
|
||||
# zram-ul de pe host absoarbe vârfurile, dar nu oprește acumularea de fond — asta o face.
|
||||
#
|
||||
# Rulează din cron ca root, ÎN INTERIORUL containerului. Conservator + idempotent.
|
||||
#
|
||||
# NU atinge:
|
||||
# - daemonul de bază /usr/lib/code-server (PPID=1 dar legitim, lansat de ttyd)
|
||||
# - procese Claude Code / node de workload (pot fi task-uri lungi legitime)
|
||||
# - sesiuni active sau procese cu părinte viu (arborele SSH e intact)
|
||||
set -uo pipefail
|
||||
|
||||
THRESH=${REAP_AGE_SECONDS:-86400} # reape doar orfane mai vechi de 24h
|
||||
LOG=${REAP_LOG:-/var/log/reap-orphans.log}
|
||||
killed=0
|
||||
|
||||
log() { echo "[$(date '+%F %T')] $*" >> "$LOG"; }
|
||||
|
||||
# 1) Forks ~/.vscode-server reparentate la init (PPID=1) și vechi => conexiune SSH moartă
|
||||
while read -r pid ppid etimes args; do
|
||||
[ "$ppid" = "1" ] || continue
|
||||
[ "$etimes" -ge "$THRESH" ] || continue
|
||||
case "$args" in
|
||||
*/usr/lib/code-server*) continue ;; # daemon de bază — păstrează
|
||||
*/.vscode-server/*) : ;; # doar serverele Remote-SSH per-conexiune
|
||||
*) continue ;;
|
||||
esac
|
||||
if kill "$pid" 2>/dev/null; then
|
||||
log "killed orphan vscode pid=$pid age=${etimes}s :: ${args:0:90}"
|
||||
killed=$((killed + 1))
|
||||
fi
|
||||
done < <(ps -eo pid,ppid,etimes,args --no-headers)
|
||||
|
||||
# 2) Sesiuni logind 'closing' cu leader mort (leader=0) => zombi siguri de terminat
|
||||
for s in $(loginctl list-sessions --no-legend 2>/dev/null | awk '{print $1}'); do
|
||||
st=$(loginctl show-session "$s" -p State --value 2>/dev/null)
|
||||
lp=$(loginctl show-session "$s" -p Leader --value 2>/dev/null)
|
||||
if [ "$st" = "closing" ] && [ "$lp" = "0" ]; then
|
||||
if loginctl terminate-session "$s" 2>/dev/null; then
|
||||
log "terminated zombie session $s"
|
||||
killed=$((killed + 1))
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
[ "$killed" -gt 0 ] && log "reaped $killed item(s)"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user