Files
nanobot-runtime/projects/devops/memory.md
2026-09-14 12:02:19 +02:00

95 lines
19 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.
- 2026-09-11: Projekt založen. Uživatel ho chce jako úložiště pro admin/root poznámky — infrastruktura, servery, provoz, podobně. Záměrně volné zaměření, strukturu a upřesnění odkládá na později. prompt.md naplněn základním homelab kontextem (Proxmox cluster, wood/pivo/nvidia/devlin.hell, Zabbix, zálohy), state.md obsahuje výchozí „kde to je / co dál".
- 2026-09-11: Presun LibreChat podman topicu z projektu ai do devops (tematicky patri sem). Artefakt librechat-podman presunut z projects/ai/artifacts/ do projects/devops/artifacts/ (README + quadlet unity). Kontext: OpenWebUI zakazano (RAM problemy), jako nahraada LibreChat; uzivatel si tema nejdřív nacte sam a rozhodne o pristupu — agent dodava info, nereshi rozhodnuti. Soucasti presunu i souhrn diskuse o podman+systemd (generate systemd deprecated od 4.4, quadlet jako hlediska, ne hotova volba).
- 2026-09-11: Doplneni motivace pro LibreChat: chci neco lite, kde snadno muzu menit LLM modely, testovat tool calling, mit preddefinovane system prompty, vyuzivat skills (LibreChat ma vlastni Skills/Agents system). OpenWebUI odstraneno kvuli RAM; LibreChat ma byt lehci alternativa s temito vlastnostmi.
- 2026-09-13: Research sandbox kontejnerů pro AI harness (LibreChat Code Interpreter). Vybrané řešení: LibreCodeInterpreter (https://github.com/GlydePath/librecodeinterpreter) — komunitní nsjail reimplementace LibreChat Code Interpreter API, Apache 2.0, GHCR image `ghcr.io/usnavy13/librecodeinterpreter` (amd64+arm64, pinovat tag, ne main). Stack: 1 API kontejner + Redis + Garage (S3). 13 jazyků (Python, JS, TS, Go, Java, C, C++, PHP, Rust, R, Fortran, D, Bash), Python REPL pool ~20-40ms exec, ostatní jazyky one-shot. Sandbox default bez sítě; ENABLE_SANDBOX_NETWORK=true zapne inline allowlist HTTPS proxy (pip/npm/cargo instally, cache ve skill-deps volume). Autentizace: x-api-key header nebo URL credentials (LibreChat LIBRECHAT_CODE_BASEURL=https://<key>@host/v1 → Basic auth).
Speciální práva kontejneru (klíčové zjištění z researchu):
- `cap_add: SYS_ADMIN` — nsjail potřebuje clone namespaces, mount, cgroups. NEVYJEDNATELNÉ, bez toho nsjail nefunguje. SYS_ADMIN je nejsilnější kontejnerová capa — kontejner s ní je de facto root co umí mountovat.
- `cap_add: NET_ADMIN` — pouze pro ENABLE_SANDBOX_NETWORK=true (iptables egress allowlist v sandbox netns). Při offline sandboxech lze vynechat.
- `security_opt: apparmor:unconfined` — nutné na hostech s AppArmor (Ubuntu/Debian), jinak mount() v nsjailu padá na EPERM. Na distrubu bez AppArmor (Alpine) no-op.
- `init: true` (tini) — reapuje zombie nsjail/python child procesy.
Význam pro nasazení: API kontejner běží jako near-host privilegia (root + SYS_ADMIN + unconfined) na sdíleném kernelu. Nejedná se o „kontejner izoluje nevěřený kód", ale „API proces musí být skoro-host, aby mohl sám izolovat kód pomocí nsjailu". Skutečná sandbox hranice pro LLM kód je nsjail (PID/mount/net namespaces, seccomp, cgroups, rlimits, non-root UID 1001) — sdílený kernel. Únik z nsjailu = kernel hostu = všechno co na něm běží.
Závěry nasazení:
- Proxmox VM > LXC pro tento use case (nevěřený LLM kód + near-host capy kontejneru). V LXC by únik z nsjailu dosáhl PVE host kernelu; VM dává druhou hranici + možnost nested virt pro microsandbox později.
- Alternativa: běží-li Docker VM jako čistý AI stack (LibreChat + interpreter, žádná produkční data), je jeden host logický celek. Na obecném provozním Docker hostu raději dedikovaná malá VM (1.5-2 GB RAM).
- Rootless podman nefunkční out-of-the-box (user namespace v user namespace, cgroup delegace) — projekt to netestuje; rootful podman/quadlet OK.
- Kompromis vs oficiální codeapi: ta řeší stejný problém microVM režimem (libkrun), ale stojí 5 komponent + Redis + MinIO.
- 2026-09-14: Záznam reportu od Claude Code (uživatel ho přinesl 2026-09-13): „Negativní zjištění — nvidia.hell / ollama" — co selhalo a co je slepá ulička z incidentů 12.13. 9. 2026. Plný report uložen verbatim jako artifact: `projects/devops/artifacts/2026-09-13_ollama-nvidia-negative-findings.md` (report odkazuje na history.md a knowledge.md na stroji, ty v workspace nejsou — jen v artifactu).
Shrnutí obsahu:
**Pojistky, které selhaly:** earlyoom zavržen a odinstalován — killuje llama-server uprostřed CUDA initu, čímž nvidia driver natrvalo ztratí napinovanou host paměť (po ~15 killech 9,27 GiB, kladná zpětná vazba: méně RAM → dřívější killy). Výchozí earlyoom konfigurace by nezasáhla nikdy (obě podmínky mem+swap musí platit současně); SIGKILL práh je polovina zadané hodnoty, musí se psát `-s 100,100`. MemoryHigh mezi spotřebou a MemoryMax = past (gemma4 host buffer 5901 MiB padl doprostřed → 84k reclaimů, load visel 600 s bez chyby) — při „rychlém selhání" se MemoryHigh nesmí nastavit. systemd-oomd nepoužit (PSI varianta earlyoomu, čekali by týž leak).
**Slepé uličky v konfiguraci ollamy:** žádný admission control v 0.33.2 (přeteče do CPU vždycky); `OLLAMA_NO_MMAP` neexistuje (issue #4895, PR #6854 nesloučen); navýšení RAM neřeší nic — podmínka mmap disable je `FreeMemory < modelSize + max(8GB, Total/10)`, headroom konstanta 7,5 GiB, potvrzeno 3 loady při různé volné paměti (uživatel RAM naopak ubral z 11,4 na 9,5 GiB); limitování počtu modelů vyhozeno (stroj shodila host RAM, ne VRAM, a MAX_QUEUE nesahá na sekvenci loadů); upgrade na 0.34.0 nic řeší; `OLLAMA_KV_CACHE_TYPE=q4_0` globálně rozbíjí modely s `n_embd_head_k=80` (granite-code padl 6×, stále nastaveno, neopraveno); gemma4 se na stroj nevejde nikdy (Per-Layer Embeddings drží embeddingy na CPU záměrně, host drží 5901 MiB i při 16 GB volné VRAM; kontraintuitivně: čím prázdnější karta, tím spíš se mmap vypne).
**Chyby v systemd konfiguraci:** StartLimit* patří do `[Unit]` (v `[Service]` se tiše ignorují); `systemctl show` property je `RestartUSec`; MemoryMax nelimituje swap → s 32 GB swapu thrashing místo OOM killu, tvrdý strop až MemorySwapMax; instalátor ollamy bezpodmínečně přepisuje unit soubor (vlastní nastavení do drop-inu, ne kopírování unitu); limity z 12. 9. z override.conf nevysvětleně zmizely (21:10 zapsány, 21:44 pryč) — příčina nezjištěna, proto záloha override.conf.bak-20260913; v drop-inu překlep `LLAMA_MAX_LOADED_MODELS` (má být OLLAMA_).
**Co nástroje neukážou:** napinovanou paměť nevidí ps/nvidia-smi/systemd-cgtop/proc-meminfo (AnonPages 135 MiB, ale anon sum 9,4 GiB) — jediný indikátor je `nr_foll_pin_acquired nr_foll_pin_released` v /proc/vmstat (skript ~/bin/nvidia-reload na nvidia.hell); sar dopad „unaccounted" paměti z 13:40 vysvětlen jako týž leak; restart ollamy leak neuvolní — paměť uteče z cgroup do system.slice, uvolní jen driver teardown/reboot; Proxmox ballooning nevhodný pro LLM stroje (počítá cíl z volné paměti hostitele, ~10 MB/s navýšení vs 17 s load modelu).
**Opravené chybné závěry:** spouštěčem nebyl LibreChat (jen zesilovač — retry po timeoutu), ale samotný model; embedding drží nanobot.hell (192.168.4.64), ne LibreChat — nanobot je zdroj dávek desítek requestů přes ~10 modelů; regrese 0.32.10 není jen Vulkan na iGPU (my CUDA + diskrétní karta, jiný spouštěč, stejný `--load-mode none`, potvrzuje #18373); leak vzniká i při zrušení loadu vlastním schedulerem po odpadnutí klienta (5,19 GiB) — nezáleží na tom, kdo llama-server ukončí, ale že to bylo uprostřed loadu.
**Upstream (otevřené/neopravené):** #18373 load regrese (2m34s vs 28s), #10104 zavřen bez řešení, #10341 gemma RAM na RTX 4060 Ti 16 GB (stejná karta, duplikát #10040), #8654 memory check vs mmap, #4895+PR#6854 mmap řízení. Problém široce hlášený, upstream neřeší.
**Drobnosti k opravě (otevřené):** zabbix-agent má defaultní `Hostname=Zabbix server` (má být nvidia); llama-server `--log-verbosity 4` (journald žral 1,9 % CPU, zaplevelený journal); LibreChat titleConvo posílá druhý souběžný požadavek na týž model; earlyoom ve stavu `rc` — zbývá `apt purge` (na disku /etc/default/earlyoom a .bak).
Koresponduje s dřívějším zjištěním z projektu ai (2026-09-13): Ollama na nvidia.hell v praxi nepoužitelná, memory watchdog zabíjí llama-server. Tenhle report dodává root cause: kill uprostřed CUDA loadu → leak napinované paměti, kterou neukáží standardní nástroje.
- 2026-09-14: Záznam druhého reportu od Claude Code: „Ollama na nvidia.hell — ucelený report" (stav k 2026-09-13 21:30). Uložen verbatim jako artifact: `projects/devops/artifacts/2026-09-13_ollama-nvidia-full-report.md`. Je to nadstavba předchozího „Negativní zjištění" reportu (uložený den předtím) — obsahuje kauzální řetěz, ověřená fakta, aktuální stav a todo list.
**Kauzální řetěz (5 kroků):** (1) ollama rozhoduje „fits alongside existing models" podle VRAM, ne volné RAM → pustí model i při system_free 115 MiB; (2) týž dechem vypne mmap (podmínka na 9,5 GiB stroji nesplnitelná nikdy) → model jde do anonymní paměti místo page cache; (3) gemma4 PLE drží 5,9 GiB host bufferu navíc; (4) RAM dojde → swap thrashing (pswpin 4512/s, %system 90 %, load 81, SSH nedostupné 45 min); (5) přerušený load → leak napinované paměti. Body [1] a [2] si odporují v téže vteřině.
**Nová fakta oproti předchozímu reportu:**
- **correction: rmmod nvidia driveru leak NEUVOLNÍ** — ověřeno 20:20, proběhl čistě, foll_pin delta bit za bit stejná (2 307 318 stránek). Moje předchozí shrnutí říkalo „uvolní ho jen driver teardown nebo reboot" — platí **jen reboot** (ověřeno 20:26: MemAvailable 89 MB → 7,6 GiB). Skript `~/bin/nvidia-reload` na stroji je tedy bezcenný.
- **Cgroup pojistka funguje a je ověřená**: `MemoryMax=6G`, `MemorySwapMax=0` (klíčový řádek — nedostupnost dělal swap thrash, ne OOM; MemoryMax sám swap nelimituje), `CPUQuota=200%`, `CPUWeight=20`, MemoryHigh záměrně vynechán. Plus SSH ochrana (`OOMScoreAdjust=-900`, `MemoryMin=32M` v ssh.service.d/10-oom-protect.conf). Zátěžový test 16:5517:05 (gemma4 load, SSH heartbeat à 2 s): 240/240 úderů, 0 výpadků, load max 3,41 (vs 81 při incidentu), MemAvailable min 3204 MiB.
- **Diagnostika OOM**: `dmesg` rozlišuje `constraint=CONSTRAINT_MEMCG` (pojistka zafungovala) vs `CONSTRAINT_NONE/global_oom` (stroj sežraný leakem, pojistka se ke slovu nedostala). `failed (Result: oom-kill)` tedy neznamená automaticky zafungovaný strop.
- **První výskyt `disabling mmap` v journalu je 2026-06-05** — předtím 13 měsíců čisto. Jde o regresi, ne stávající vlastnost.
- **`sar` chybějící vzorek = sám o sobě důkaz** (stroj nestíhal ani cron à 10 min) — datování začátku incidentu.
- **Zavržené nově:** zvedání `OLLAMA_LOAD_TIMEOUT` („turns a hard failure into a slow success" — jen by prodloužilo thrashing); Proxmox ballooning → řešení `balloon: 0` + pevná paměť (pvestatd počítá cíl z volné paměti hostitele, ~10 MB/s vs 17 s load modelu).
- **Capability `tools` ≠ model nástroje použije**: mistral:latest dostal stejných 5 nástrojů jako glm-5.3, nezavolal ani jeden; flag říká jen, že šablona podporuje tools. Seznam modelů bez `tools` capability (nikdy nebudou fungovat): llama3, llama2-uncensored, tinyllama, aya, phi4, phi3.5, codellama, exaone-deep, deepseek-coder-v2, granite-code:8b.
- **Prostředí:** VM pod pve.hell (192.168.4.47), RAM snížena 11,4 → 9,5 GiB, swap 32 GB swappiness=60, 4 jádra, RTX 4060 Ti 16 GB, ollama 0.33.2 nativně. Skutečný zdroj zátěže = nanobot.hell (192.168.4.64), LibreChat jen zesilovač.
- **Kuchařka pro triáž** (awk foll_pin delta, kontrola cgroup limitů — už jednou zmizely, constraint grep, journalctl IP grep, sar postmortem) + **zálohy a rollback** (override.conf.bak-20260913, ~/backup/ollama-20260912-2108/, upgrade skripty).
**Otevřené body (prioritně, z §11):** (1) zastavit dávky z nanobot.hell — bez toho leak zpátky během minut; (2) retest cgroup pojistky bez MemoryHigh (odblokováno rebootem, kritéria: heartbeat bez výpadku, MemAvailable > 2 GiB, constraint=MEMCG); (3) doladit MemoryMax podle memory.peak z retestu; (4) rozhodnout osud gemma4 (PLE ~5,9 GiB host bufferu, na 9,5 GiB stroji nikdy); (5) OLLAMA_KV_CACHE_TYPE=q4_0 zrušit nebo nepoužívat granite-code; (6) drobnosti: apt purge earlyoom, log-verbosity 4, zabbix Hostname, LibreChat titleConvo, otázka monitoringu (hlídač co killuje = zavržená cesta).
**Stav po rebootu 20:26:** stroj zdravý (MemAvailable 7,6 GiB, 0 OOM killů), pojistka aktivní ve správné podobě.
- 2026-09-14: correction: K bodu „Zastavit dávky z nanobot.hell (192.168.4.64)" z reportu i mého shrnutí z 2026-09-14 — nanobot.hell **není trvalý zdroj zátěže**. Dávky chat requestů přes ~10 modelů byly **testovací tool-calling requesty** (testy schopností lokálních modelů, viz projekt ai, memory 2026-09-12/13 — skript `projects/ai/artifacts/ollama-toolcall-test.py`). Jednorázová testovací zátěž, ne provoz.
Běžný provoz nanobota na lokální ollamu **nesahá**: používá ji jen na (a) embeddingy (`qwen3-embedding:0.6b` pro wiki skill, periodicita z wiki syncu) a (b) cloud modely (`:cloud` presety, `glm`/`kimi` — ty neběží lokálně, jen se proxy přes ollama endpoint). Chat na lokálních modelech není součást provozu.
Důsledek pro open body: bod 1 reportu („zastavit dávky z nanobotu — bez toho leak zpátky během minut") **neplatí jako provozní riziko**, jen jako poučení pro případné budoucí testovací dávky. Zbylé open body (retest pojistky, MemoryMax, gemma4, KV_CACHE_TYPE, drobnosti) zůstávají. Trvalé součásti povrchu nanobot→ollama zůstávají embeddingy — izolace embeddingů na samostatný statický server (llama.cpp/vLLM) tím dává ještě větší smysl: po ní lokalně nezůstane téměř žádný nanobot provoz, který by ollamu mohl shodit.
- 2026-09-14: Závěr embed-parity snažení (qwen3-embedding:0.6b, ollama vs llama.cpp server na :8081, `--pooling last`): parita **neexistuje** — stejné vstupy dávají fundamentálně odlišné vektory (i jednotokenový vstup `cat` → cosine 0,36; delší vstupy 0,870,93), reuse ollama blobu v llama.cpp paritu nezajistí, pooling ani input wrapping (speciální tokeny, chat template) rozdíl nevysvětlují (vše systematicky vyzkoušeno a vyloučeno). Uživatelovo závěrečné rozhodnutí: **při přechodu na čistý llama.cpp se reindexuje celá wiki báze** — žádná snaha o bezreindex migraci; přepnout endpoint v wiki/config.yaml na nvidia.hell:8081 + full reindex jedním krokem.
- 2026-09-14: Z článku "10 Linux Tools" potvrzený stávající tooling: uživatel používá tmux, lazydocker, bat, mosh. Z výčtu nevyužité kandidáti: fzf, zoxide, ripgrep, fd, delta, btop.
- 2026-09-14: Druhý článek ("10 CLI Tools That 10x Backend Productivity") — potvrzeno: just už zkoušel a líbí se mu hodně (jedina výtka: málo rozšířený), jq používá, zůstává u curl (httpie viděl, ale nepřepnul). Další kandidáti z článku k nezavedení: watchexec/entr, xh, eza, mise, pgcli, gh.
- 2026-09-14: Z článku (Medium, DataExpert, 2026-09-03) a online verifikace — poznámka ke stacku DuckDB + Apache Iceberg + dbt:
Use case: celý enterprise lakehouse workflow (incremental loading, SCD Type 2, partition pruning, schema evolution, data quality testy, compaction) lze prototypovat a učit na laptopu za $0, místo placeného Snowflake/Databricks compute. dbt-duckdb adapter = stejné SQL/modely lokálně i na produkci (Snowflake/BigQuery), mění se jen dbt target. Relevance pro homelab: levná varianta pro vlastní analytické pipeline na malých/ Středních datech (10100 GB), kde by jinak byl nutný Spark cluster.
Ověřené fakta (primární zdroje):
- DuckDB v1.5.3 (2026-05-29): plná podpora zápisu do Iceberg tabulek — MERGE INTO (merge-on-read, positional deletes), ALTER TABLE (schema evolution, metadata-only), partition transforms bucket/truncate, Iceberg V3 (deletion vectors jako Puffin, VARIANT, TIMESTAMP_NS). Dřív jen čtení; zápis vyžadoval Spark. Zdroj: https://duckdb.org/2026/05/29/new-iceberg-features a https://duckdb.org/2025/11/28/iceberg-writes-in-duckdb
- DuckLake v1.0 (2026-04-13): lakehouse formát, metadata v SQL databázi (catalog SQLite/Postgres/DuckDB) místo metadata souborů v object storage; data inlining (default threshold 10 řádků) řeší small-file problem; volitelná Iceberg kompatibilita. Zdroj: https://ducklake.select/2026/04/13/ducklake-10/
- Apache Polaris: free self-hostable Iceberg REST catalog, top-level Apache projekt (únor 2026) — náhrada Hive Metastore/Glue pro lokální setup.
- AWS acquirenul DuckLabs (tým za DuckDB, srpen 2026); projekt zůstává MIT pod nezávislou DuckDB Foundation.
Benchmarky jen z Medium článku, neověřitelné, brát s rezervou: FinQore pipeline 8 h → 8 min (60×, migrace z Postgres); dashboard dotazy 200400 ms vs 25 s Snowflake X-Small; MotherDuck 67× rychlejší než ekvivalentně ceněné Snowflake/Redshift na 10100 GB.
Limity stacku: DuckDB 1 writer (multi-process writes selhávají), Iceberg+Parquet 23× pomalejší než nativní DuckDB formát, small-file/manifest explosion se na laptopových datech neprojeví — produkční operační zkušenost se musí nabýt na produkci.
- 2026-09-14: Poznámka z článku (Medium, Jesse L, ~2026-11): **Posting** — TUI HTTP klient jako alternativa k Postman/Insomnia. Relevance pro homelab: běží v terminálu přes SSH, takže se dá testovat API přímo ze stroje, který na něj dosáhne (uvnitř VPC, za bastionem, interní služby v Proxmox/LXC) — žádný port forwarding ani tunel GUI klientu.
Klíčové fakta:
- Python + Textual framework; zdroj https://github.com/darrenburns/posting, dokumentace https://posting.sh; verze k psaní článku v2.10.0
- Instalace: `uv tool install --python 3.13 posting` (izolovaný Python, nesahá na systémovou verzi); Homebrew/NixOS oficiálně nepodporované
- Requesty jsou čitelné **YAML soubory** (`.posting.yaml`), kolekce = adresář — commitovatelné vedle kódu, čitelné diffy v PR, žádný export/import JSON s generovanými ID
- Prostředí přes `.env` soubory: `posting --env dev.env` / `posting --env staging.env` — stejné env soubory jako zbytek projektu, tajemství se necommitují
- Import z Postman/OpenAPI: `posting import -t postman collection.json` / `-t openapi openapi.yaml` — z OpenAPI specu lze vygenerovat sadu requestů bez ruční práce
- Klávesy: `Ctrl+P` command palette (jako VS Code), `Ctrl+J` odeslat, Tab/j/k navigace, jump mode s písmeny na widgetech
- Konfig: `~/.config/posting/config.yaml` (témata, keybindings, default headers) → vhodné do dotfiles repa; default kolekce `~/.local/share/posting/default`
- `posting locate config` / `posting locate collection` vypíše cesty
Kdy se nehodí: automatizované testy/CI (na to pytest+httpx nebo newman), sdílené workspaces/mock servery (komerční klienty), API design/dokumentace.
Alternativy: **atac** (Rust TUI, podobný cíl), **httpie**/**curlie** (CLI, rychlejší na jednorázovky), **Bruno** (GUI, ale stejná file-based Git-friendly filozofie).
Vzetá idea i bez instalace: API requesty patří do repa jako soubory vedle kódu, který testují — ne do proprietárního formátu v cizím cloudu.