docs: llama.cpp in k3s (Task 6.1), Device Plugin nur M4000, VRAM-Befund
ci / test (push) Failing after 22s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Robert Rapp
2026-10-19 17:49:12 +02:00
co-authored by Claude Opus 5.5
parent 862825fa1e
commit f9036934c3
3 changed files with 11 additions and 4 deletions
+2 -1
View File
@@ -225,7 +225,7 @@ Die GPU-VMs bilden mit der Dienst-VM `k3s` einen k3s-Cluster (v1.36.5+k3s1). Ste
| Manifeste | `deploy/k8s/` (RuntimeClass `nvidia`, NVIDIA Device Plugin v0.20.1, Portainer Agent 2.45.2, `nex-speech/`, `nex-searxng/`, `rustdesk/`) |
| Playbooks | `playbooks/k3s.yml` (Server, Agents, Grundausstattung), `playbooks/nex-speech-k3s.yml`, `playbooks/nex-searxng-k3s.yml`, `playbooks/rustdesk-k3s.yml` (Umzüge), `playbooks/monitoring-k3s.yml` (Pod-Monitoring) |
| Monitoring | kube-state-metrics v2.19.1 in `kube-system` (NodePort 30808), Prometheus auf infra liest kubelet/cAdvisor; Grafana-Dashboard „k3s – Pods“ (Abschnitt 7). `kubectl top` zeigt weiter den metrics-server von k3s |
| GPU in Pods | `runtimeClassName: nvidia` + `resources.limits: {nvidia.com/gpu: 1}`; Knoten-Labels `knaster.gpu=true`, `knaster.gpu.m4000=1`, `knaster.gpu.p2000=1` |
| GPU in Pods | `runtimeClassName: nvidia` + `resources.limits: {nvidia.com/gpu: 1}` vergibt seit 19.10. nur die M4000 (Device Plugin sieht nur Index 0, allocatable 1/1/1/1). Die P2000 gehört fest llama.cpp (`NVIDIA_VISIBLE_DEVICES=<UUID>`, kein `nvidia.com/gpu`). Knoten-Labels `knaster.gpu=true`, `knaster.gpu.m4000=1`, `knaster.gpu.p2000=1` |
| Portainer | Umgebung „Kubernetes → Agent“ mit Adresse `<IP eines Knotens>:30778`, z. B. `192.168.100.124:30778` (Agent-Pod läuft im Namespace `portainer`) |
- **Zuteilung (seit 15.10.):** jede GPU-VM hat alle 8 Threads und 20 GB ihres Knotens (`vms.*.cores/memory_mb` in der Site-Datei), der Cluster zeigt damit 34 vCPU und 83 GB. Der Rest je Knoten (32 GB): Proxmox ~3 GB, ZFS-ARC 2 GB (`cluster.zfs_arc_max_mb`, Rolle pve-host, sofort wirksam), dazu ops 2 GB (pve46), infra 4 GB (pve44), k3s 3 GB (pve48). RAM der GPU-VMs ist wegen PCI-Passthrough fest reserviert. Ändern: Site-Datei, auf ops `tofu apply` (startet nicht automatisch neu, `reboot_after_update = false`), dann je Knoten `qm reboot <vmid>` nacheinander und `kubectl get node` abwarten. Knapp wird es nur im HA-Fall, wenn infra und k3s gleichzeitig auf denselben Ersatzknoten ziehen.
@@ -235,6 +235,7 @@ Die GPU-VMs bilden mit der Dienst-VM `k3s` einen k3s-Cluster (v1.36.5+k3s1). Ste
- **Portainer CE im Cluster** (seit 15.10., Namespace `portainer-ce`, Pod auf der Dienst-VM k3s, Daten auf deren local-path, `https://192.168.100.124:30779`): Datenbank aus dem Volume `portainer_data` von appsrv08 (Portainer EE 2.45.1) übernommen, mit dem offiziellen Werkzeug `portainer-ee --rollback-to-ce` auf Community Edition zurückgesetzt (laut Portainer-Doku nur nach CE→BE-Upgrade möglich, hat bei der frischen BE-Installation trotzdem funktioniert; CE verweigert eine BE-Datenbank sonst mit Hinweis). Benutzer, Passwörter, API-Schlüssel und Umgebungen sind erhalten, der Schlüssel aus `it/.hermes.env` funktioniert unverändert. Sicherung `/root/.config/knaster/portainer_data.tgz` auf ops (15.10., 2,5 MB). **Umgebungen:** Nr. 4 „godel-local“ war der Docker-Socket von appsrv08 und ist im Cluster tot; auf appsrv08 läuft dafür `portainer_agent` (2.45.1, nur `192.168.100.29:9001`), den ein Admin als neue Umgebung „appsrv08“ (Agent) anlegt und für `godel-deployer` freigibt. Die Kubernetes-Umgebung (Nr. 5, Agent `:30778`) bleibt. **Noch auf appsrv08:** Portainer EE (`:9443`) läuft parallel weiter, nginx leitet `portainer.mygodel.de` dorthin; Umstellung = `proxy_pass` in `/var/docker/nginx/etc/nginx/conf.d/portainer.conf` auf `https://192.168.100.124:30779`, `nginx -t`, Reload (Runbook `IT Verbesserungen/GRP_Linux/Portainer-DNS-Runbook.md`), dann EE stoppen. Für nex-Admin und `.hermes.env` (URL `:9443`, Endpoint 4) zusätzlich Weiterleitung `:9443` → Cluster oder Werte anpassen. Lizenz: CE hat keine Knotengrenze.
- **Agenten im Cluster (NEX)** (seit 19.10., nex-Spec `docs/specs/2026-10-19-nex-cluster-agenten-design.md` im nex-Repo): Neue Hermes-Agenten entstehen als Deployment im Namespace `nex`, angelegt von nex-admin auf appsrv08 über die Kubernetes-API (`playbooks/nex-k3s.yml`: ServiceAccount `nex-admin` mit Role nur für diesen Namespace, Token auf ops `/root/.config/knaster/nex-admin-k8s.token`, Pull-Secret `gitea-registry` aus `/root/.config/knaster/gitea-registry.env`). Die Pods erreichen die NEX-Dienste auf appsrv08 über Services ohne Selector (`deploy/k8s/nex/bridge.yaml`: nex-router 4100, nex-know 14200 (Host-Port, Service-Port 4200), nex-access 4300, grp-mcp-intern 8790 → `192.168.100.29`, dort als Host-Ports nur auf dieser Adresse veröffentlicht). Nutzeradressen bleiben `https://192.168.100.29:<port>/`: Traefik auf appsrv08 leitet an den NodePort `<port>+20000` weiter. Agenten-Volumes liegen auf `local-path` (an den ersten Knoten gebunden).
- **RustDesk-Server** (ID-Server hbbs + Relay hbbr) läuft seit 15.10. zusätzlich in k3s (Namespace `rustdesk`, ein Pod auf einem GPU-Knoten, Datenbank auf `local-path`, Service-Typ LoadBalancer: Ports 21115–21119/tcp und 21116/udp auf **jeder** Knoten-Adresse). Das Schlüsselpaar ist dasselbe wie auf appsrv08 (Kopie auf ops `/root/.config/knaster/rustdesk/`, im Cluster als Secret `rustdesk-keys`), der Public Key der Clients `BPhsgjAI8yicpNRA3YsnBzfx78JUuNglrYZSZANVCUY=` bleibt gültig. hbbs nennt den Clients als Relay die Adresse `rustdesk_public_host` (Standard: k3s-VM, Variable im Playbook). **Umstellung der Clients steht aus:** sie tragen heute `192.168.100.29` als ID-Server; nötig sind eine feste Adresse (DHCP-Reservierung der k3s-VM oder DNS-Name am DC) und danach die neue Adresse in den installierten Clients sowie im Installer-Namen des Portainer-Stacks `rustdesk-updater` (`SERVER_HOST`). Bis dahin läuft der Stack `rustdesk` auf appsrv08 weiter.
- **llama.cpp** (Task 6.1, seit 19.10.) läuft in k3s, Namespace `knaster`, ein Deployment `llamacpp-<vm>` je GPU-VM: Embedding 8081 + Rerank 8082 auf gpu-pve44/46 (zwei Container, eine P2000), Chat 8080 auf gpu-pve48. Host-Netz, Ports und Prometheus-Ziele wie zuvor im Compose. Ausrollen: `playbooks/gpu-llamacpp-k3s.yml` (prüft, dass Index 0 die M4000 ist, wendet das Device Plugin an, dann VM für VM). Rückweg je VM: `kubectl -n knaster delete deploy llamacpp-<vm>`, in der VM `docker compose --project-directory /opt/knaster/gpu-llamacpp start`; `playbooks/gpu-llamacpp.yml` nur mit `-e llamacpp_compose=true`. Embedding mit `-ub 4096`, weil `-ub 8192` 5 GB Rechenpuffer bräuchte.
- **Images** aus Compose-Builds landen per `docker save | k3s ctr images import -` im containerd von k3s (Rolle nex-speech-k3s); kein Registry nötig. Für neue Dienste ohne Build reicht `image:` aus Docker Hub oder nvcr.io.
- **ufw in den VMs:** die Rolle k3s-agent erlaubt 10250/tcp, 8472/udp, 30000–32767/tcp aus dem LAN und alles aus dem Pod-Netz 10.42.0.0/16.
- **Aktualisieren:** `k3s_version` in `roles/k3s-server/defaults` und `roles/k3s-agent/defaults` anheben, `playbooks/k3s.yml`; erst Server, dann Agents (so läuft das Playbook). Kubernetes-Versionen immer nur eine Minor-Stufe je Schritt.
@@ -302,7 +302,7 @@ Ersetzt GPU-Knoten 3 (Teil Cluster). Mit 5 Stimmen ist **kein QDevice** nötig.
- [ ] Strom je Knoten: Leerlauf und Volllast beider Karten (400-W-Netzteil, erwartet etwa 300 W).
- [ ] Ergebnis eintragen in `catalog/models.yaml` und `sites/knaster/registry.yaml`, in ADR-0006 „M4000 wieder aufnehmen ja/nein“ und in die STT-Entscheidung D131/D133 (nex). Commit.
- [x] (12.10.) Katalog: `vram_gb` gemessen (Embedding 2,8, 4B 4,1, 8B 7,8 aufgerundet) und Messwerte als `note`. Die Registry hat keine Felder für Messwerte und bleibt unverändert. ADR-0006 Nachtrag „Benchmark“: M4000 **ja für STT auf pve52**, auf pve44/46/48 vorerst nein (P2000 gleich schnell bei halber Leistung). `knaster validate` und `pytest core` grün (außer dem bekannten Windows-Fehler in `test_tts_server`), Placement unverändert, alle aktiven Rollen auf gemessenen P2000.
- [ ] Offen: STT-Entscheidung D131/D133 im nex-Repo, `disabled` der M4000 auf pve52 erst nach der Strommessung (Nutzer). Rerank-VRAM neben Embedding auf der P2000 ungemessen. Für Task 6.1: Compose `count: 1` greift die M4000, `device_ids` setzen.
- [ ] Offen: STT-Entscheidung D131/D133 im nex-Repo, `disabled` der M4000 auf pve52 erst nach der Strommessung (Nutzer). Rerank-VRAM neben Embedding: 19.10. gemessen, passt mit `-ub 4096` (Task 6.1). Für Task 6.1: Compose `count: 1` greift die M4000, `device_ids` setzen.
Prüfung: `make validate` → PASS, Placement ordnet jede aktive Rolle einer gemessenen Karte zu.
---
@@ -365,8 +365,13 @@ Ersetzt PLAN §8 „1 Data Plane“.
- [x] (15.10.) Umzug 3: RustDesk-Server (Stack `rustdesk` auf appsrv08) als Deployment + Service LoadBalancer in k3s (`playbooks/rustdesk-k3s.yml`), gleiches Schlüsselpaar, Ports auf allen Knoten erreichbar. Clients zeigen weiter auf .29; Umstellung erst mit fester Adresse/DNS-Name (Nutzer), dann Installer-Name im Stack `rustdesk-updater` und Stack `rustdesk` auf appsrv08 abschalten.
- [x] (15.10.) Umzugstest 2 aus Portainer-Umgebung appsrv08: SearXNG (`nex-searxng`) als Deployment + NodePort 30880 in k3s, Suche liefert Treffer. Cutover: Nutzer hat 15.10. Weg 2 gewählt (SEARXNG_URL im nex-Admin als Stack-Variable konfigurierbar machen, nex-Repo), Rollout nach DHCP-Reservierung der k3s-VM.
- [x] (19.10.) Agenten im Cluster (nex-Spec 2026-10-19 D256–D267): Namespace nex mit Brücke zu appsrv08 (Services ohne Selector: router 4100, know 14200, access 4300, grp-mcp-intern 8790), ServiceAccount nex-admin (Role nur Namespace, Token auf ops), Playbook `playbooks/nex-k3s.yml`; nex-admin 0.2.1 auf appsrv08 legt neue Agenten als Deployment/PVC/Secret/NodePort-Service an, Umzug per UI/API, Traefik auf appsrv08 leitet Port-Adressen an NodePort <port>+20000. Offen: Pull-Secret `gitea-registry` (Gitea-Token read:package in /root/.config/knaster/gitea-registry.env, dann Playbook), Umzugsprobe nextest3, feste Adresse der k3s-VM (NEX_K3S_HOST).
- [ ] Offen: Umgebung in Portainer (appsrv08) anlegen (Nutzer, 15.10. laut Nutzer erledigt), DHCP-Reservierung für VM 110 (`bc:24:11:a5:d5:52`), llama.cpp (6.1) direkt als k3s-Manifeste statt Compose, Monitoring der Pods (Task 6.5), Exporter-Stacks umziehen, Docker danach aus den VMs entfernen.
- [ ] Offen: Umgebung in Portainer (appsrv08) anlegen (Nutzer, 15.10. laut Nutzer erledigt), DHCP-Reservierung für VM 110 (`bc:24:11:a5:d5:52`), llama.cpp (6.1, seit 19.10. in k3s), Monitoring der Pods (Task 6.5), Exporter-Stacks umziehen, Docker danach aus den VMs entfernen.
- [ ] **6.1 GPU-Rollen:** ab 15.10. als k3s-Manifeste (D6) statt Compose: `deploy/compose/gpu-llamacpp` in den GPU-VMs nach der Zuordnung aus Task 3.3, also Embedding und Rerank redundant auf zwei Knoten, Chat für verifier und signature. Prüfung: Canary-Checks grün (`knaster` Canary-Prober).
- [x] (19.10.) llama.cpp läuft in k3s (`playbooks/gpu-llamacpp-k3s.yml`, Rolle gpu-llamacpp `tasks/k3s.yml`, Vorlage `deploy/k8s/llamacpp/llamacpp.yaml.j2`, Namespace `knaster`): ein Pod je VM, Host-Netz mit den alten Ports (8081/8082 auf gpu-pve44/46, 8080 auf gpu-pve48), Image aus Docker in containerd importiert. Compose-Stack auf gpu-pve48 angehalten (Rückweg: Deployment löschen, `docker compose --project-directory /opt/knaster/gpu-llamacpp start`); `playbooks/gpu-llamacpp.yml` bricht ohne `-e llamacpp_compose=true` ab.
- [x] (19.10.) Kartenwahl: Das Device Plugin vergibt nur noch Index 0 (M4000, per Playbook auf allen GPU-VMs geprüft), allocatable `nvidia.com/gpu` 1/1/1/1 statt 2/2/2/1. Die P2000 bekommt der llama.cpp-Pod fest per UUID (`NVIDIA_VISIBLE_DEVICES`); im Pod ist nur sie sichtbar, `nex-stt` lief durch.
- [x] (19.10.) Befund VRAM: Embedding mit `-ub 8192` braucht allein 5 GB Rechenpuffer (wächst mit ub × Vokabular 151k), Flash-Attention ändert daran nichts. Mit `-ub 4096`: Embedding + Rerank zusammen 4,4–4,6 von 5 GB auf der P2000, Chat 4,1 GB. Auch im Compose (Rückweg) angepasst.
- [x] (19.10.) Prüfung statt Canary (die Canaries fragen über LiteLLM, das kommt mit 6.3): Prometheus `llamacpp` 5/5 `up`; vom LAN (ops) liefern beide Embedding-Instanzen 1024-dim Vektoren (0,06–0,08 s), beide Rerank-Instanzen sortieren richtig, Chat antwortet „OK.“ (0,46 s); 5.467 Tokens in einem Embedding-Aufruf (11,6 s).
- [ ] Offen: Canary-Checks grün nach 6.3. Registry und Healer-Regeln führen noch `docker_host`/`container` (Aktion `restart_container` träfe einen Docker-Container, den es nicht mehr gibt); heute folgenlos (Dry-Run, `enabled_actions: []`), vor dem Scharfschalten auf Pod-Neustart umstellen.
- [ ] **6.2 STT und TTS für NEX** – Auftrag vom 12.10. mit Abgleich: `docs/auftraege/2026-10-12-sprachmodelle-nex.md` (Erkennung whisper.cpp auf einer M4000, naheliegend `gpu-pve52`; Ausgabe Piper auf CPU, Port 8179; Abnahme und Rückmeldeformat dort). Läuft nach Task 3.2, gern als Subagent. **Blockiert für die Abnahme:** feste IP (D5). Bisheriger Text (nex-STT-Plan Tasks 2–4): `whisper-server` als zusätzlicher Dienst in der GPU-VM des in Task 3.3 gewählten Knotens. Neuer Slot `stt-de` im Katalog. Port 8178 nur von `192.168.100.29` (Firewall der VM bzw. des Gasts). Prüfung: Von appsrv08 liefert `curl -F file=@probe.wav http://<IP>:8178/v1/audio/transcriptions` deutschen Text, von einem anderen Rechner wird der Zugriff abgelehnt.
- [x] (12.10.) Umgesetzt in `gpu-pve52`: `nex-stt` (whisper.cpp v1.9.4, CUDA 12.6, sm_52/61, `large-v3-turbo`, Port 8178) und `nex-tts` (Piper 1.8.0, `de_DE-thorsten-high` + `de_DE-kerstin-low`, Port 8179) als `deploy/compose/nex-speech`, Rolle/Playbook `nex-speech`. ufw in der VM (8178/8179 nur von `.29`, SSH aus dem LAN), Proxmox-Firewall bewusst aus.
- [x] (12.10.) Tests in der VM und von ops (temporäre Regel, danach entfernt): 10 s → 2,94 s, 60 s → 8,63 s (Median), TTS-TTFB 0,64–0,91 s (mp3/pcm/opus), Autostart nach `qm reboot 252` geprüft, keine Texte in Logs. Rückmeldung im Auftrag.