Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
28 KiB
Betrieb: Skill-Lebenszyklus, Hermes, Pflege, Freischaltung, Proxmox-Cluster
1. Lebenszyklus eines Skills
Hermes schreibt SKILL.md
│
draft ──(Mensch/Agent: aktivieren)──▶ active, Stufe 0
│ läuft auf dem starken Modell mit Skill-Text,
│ sammelt verifizierte Fälle
Service-Routine: stabil ≥ 95 % ────┤
▼
request_graduation (Freigabe)
│ Hermes erzeugt Varianten →
│ POST /v1/skills/{name}/graduate
▼
promote_skill (Freigabe) ──▶ active, Stufe 1 (schwaches Modell)
│
Drift (Pass-Rate < 80 %) ──▶ demote_skill (automatisch) ──▶ demoted (Stufe 0)
│
≥ 300 Trainingsfälle, Stufe-1-Rate < 90 % ─▶ train_adapter (Freigabe) ──▶ Lifecycle-Pipeline
Stufe 2 (Programm) und Stufe 3 (Classifier) gibt es, wenn der Skill execution: program|classifier deklariert und die passende Stufe freigegeben ist. Programme liegen in knaster/programs.py und gehen wie normaler Code durch ein Review. Classifier entstehen aus gelabelten Fällen (EmbeddingClassifier.train) und liegen unter config/classifiers/<name>.json.
2. Rolle von Hermes
Hermes läuft als Skill-Autor mit dem starken Modell. Er zeigt auf LiteLLM, Alias tier0-strong. Hermes steht nicht im Pfad jeder Anfrage.
| Auslöser | Hermes tut | Schnittstelle |
|---|---|---|
Job graduate_skill (über n8n knaster-jobs) |
10–30 realistische Varianten erzeugen, Graduierung aufrufen. Schlägt sie fehl, den Skill anhand von failures überarbeiten |
POST /v1/skills/{name}/graduate |
Job merge_skills |
zwei Skills zu einem zusammenführen, alten Skill auf retired setzen |
Git-Commit in skills/, dann POST /v1/skills/reload |
Neue Aufgabenklasse (häufige no_skill-Fälle) |
neuen SKILL.md-Entwurf schreiben (status: draft) |
Git-Commit + Reload |
Skills sind Dateien im Repo. Jede Änderung ist dadurch ein nachvollziehbarer Commit und lässt sich zurückdrehen.
3. Pflege per Prompt (Beispiele)
> routine
Service-Routine
Befunde:
- Drift: zusammenfassung Pass-Rate 72% (n=40)
Automatisch erledigt:
- P-12: Skill zusammenfassung auf Stufe 0 zurückstufen → Skill zusammenfassung auf Stufe 0 zurückgestuft
Offene Vorschläge (genehmige P-x / lehne P-x ab):
- P-13 [low] LoRA-Adapter für rechnungen trainieren – 412 verifizierte Fälle, Stufe-1-Rate 86%
> genehmige P-13
P-13 executed: Kandidat 7f3e… (adapter) angelegt und Build gestartet
> wechsle tier1-general auf qwen3-32b-awq
Vorschlag P-14 [medium] Basismodell von tier1-general auf qwen3-32b-awq wechseln …
Bestätige mit „genehmige P-14“.
Freitext, der keinem Befehl entspricht, bildet ein kleines Modell auf einen Befehl ab. Der Agent fragt dann mit „Meinst du …?“ zurück.
4. Dry-Run aufheben (schrittweise)
- Eine Woche mit
KNASTER_DRY_RUN=truelaufen lassen. Die Healer-Ergebnisse stehen als[dry-run] …in den Antworten bzw. Logs. KNASTER_DRY_RUN=falsesetzen. Interne Aktionen (Slot-Status, Skill-Stufen, Kandidaten) liefen schon vorher. Jetzt werden auch Jobs per Webhook verschickt.- Infrastruktur-Aktionen einzeln freischalten, über
config/healer-rules.yaml→enabled_actions: [restart_container], späterrestart_vm.reboot_hostbleibt freigabepflichtig (Policy) und läuft nur im Wartungsfenster.
5. Rollback-Wege
| Was | Wie |
|---|---|
| Adapter/Basismodell | Prompt rollback <slot> → Freigabe |
| Skill-Stufe | Prompt stufe <skill> zurück bzw. Git-Revert der SKILL.md |
| Treiber/Engine | Proxmox-Snapshot der GPU-VM (vor jedem Update anlegen) |
| Konfiguration | Git-Revert und Neustart des Router-Containers |
6. Proxmox: Updates und Neustarts (rollierend, Knoten für Knoten)
Stand 12.10.2026, getestet mit dem Wartungsmodus auf pve44. Gilt für pve44, pve46, pve48, pve52 und pve61.
Wichtig vorab
- Auf den GPU-Knoten gehört die M4000 (Boot-Grafik) der VM. Nach dem frühen Start bleibt der lokale Bildschirm schwarz. Zugang nur per SSH oder Weboberfläche; das GRUB-Menü ist beim Start noch sichtbar (Notzugang: Eintrag bearbeiten,
initcall_blacklist=sysfb_initentfernen). - pve61 hängt am Netz nur über die USB-NIC im Dock. Neustart nur, wenn jemand vor Ort ist. Kommt er nach etwa 2 Minuten nicht zurück: Dock aus- und wieder einstecken.
- Nie zwei Knoten gleichzeitig. Mit 5 Stimmen bleibt das Quorum bei einem fehlenden Knoten erhalten.
Ablauf je Knoten
- Vorher:
pvecm status(Quorate: Yes),ha-manager status,pvesr status(alle Jobs OK). - Wartungsmodus:
ha-manager crm-command node-maintenance enable <knoten>. HA-Gäste ziehen um (infra: Test 36 s nach pve48). - GPU-VM des Knotens sauber stoppen:
qm shutdown <vmid>(244/246/248/252). Sie hat kein HA und kann nicht wandern (Passthrough). - Update:
platform/proxmox/scripts/bootstrap-node.sh <knoten>vom Laptop (idempotent, meldetNeustart nötig), dannreboot. - Nachher prüfen: Kernel,
systemctl --failed,ip -br a show vmbr0, NTP; auf GPU-Knotenlspci -nnk -d 10de:→ überallvfio-pci. - GPU-VM startet von selbst (
onboot). Danach auf ops:cd /root/cluster-knaster/platform/proxmox/tofu && . /root/.config/knaster/tofu.env && bash ../scripts/refresh-vm-access.sh(DHCP-Adressen können wechseln, Hostschlüssel kommen über den Gast-Agenten) undansible gpu_vms -m shell -a "nvidia-smi -L". - Wartungsmodus aus:
ha-manager crm-command node-maintenance disable <knoten>. HA holtinfraauf seinen Heimatknoten pve44 zurück (Test 41 s).
GPU-VMs aktualisieren
- Pakete per
aptin der VM, die NVIDIA-Pakete sind aufhold(R580). Vor Treiberwechseln einen Snapshot anlegen:qm snapshot <vmid> vor-treiber. - Nach einem VM-Neustart immer
refresh-vm-access.sh, solange es keine DHCP-Reservierungen gibt (D5).
7. Infra-Stack und Monitoring (LXC infra)
Stand 12.10.2026 (Task 5.2). Der LXC infra (vmid 101, HA, Heimat pve44, Replikation nach pve48/pve52) führt einen Compose-Stack knaster-infra: Router (Dry-Run), TTS (Piper), Postgres, Prometheus, Alertmanager, Grafana, pve-exporter, node-exporter, autoheal. Kein eigener LiteLLM (D4).
Adressen (DHCP, die IP kann sich nach einem Umzug ändern; aktuelle IP: ansible infra -m debug -a var=ansible_host auf ops oder refresh-vm-access.sh)
| Dienst | URL | Anmeldung |
|---|---|---|
| Grafana | http://<infra-IP>:3000 |
admin bzw. kiosk (Viewer) |
| Prometheus | http://<infra-IP>:9090 |
ohne (nur LAN) |
| Alertmanager | http://<infra-IP>:9093 |
ohne (nur LAN) |
| Router | http://<infra-IP>:8080 |
Bearer-Token |
Wo liegt was
- Konfiguration im Repo:
deploy/compose/infra,deploy/prometheus,deploy/alertmanager,deploy/grafana(Datasource, Dashboards). Im LXC als Kopie unter/opt/knaster/repo(wird bei jedem Ansible-Lauf abgeglichen, dort nichts ändern). - Geheimnisse nur im LXC, nie im Repo:
/opt/knaster/infra/.env(0600) mitPOSTGRES_PASSWORD,KNASTER_API_TOKEN,GRAFANA_ADMIN_PASSWORD,GRAFANA_KIOSK_PASSWORD(beim ersten Lauf mitopenssl randerzeugt, danach nie überschrieben). Lesen:ssh root@<infra-IP> grep ^GRAFANA_KIOSK_PASSWORD= /opt/knaster/infra/.env(für den Kiosk, Task 5.3). /opt/knaster/infra/secrets/router_token(Kopie vonKNASTER_API_TOKENfür den Alertmanager) undsecrets/pve-exporter.env(Kopie von ops/root/.config/knaster/pve-exporter.env, Tokenmonitoring@pve!prom, PVEAuditor).- Einstellungen ohne Geheimnis (Dry-Run,
LITELLM_BASE_URL…) stehen inplatform/proxmox/ansible/roles/infra-stack/defaults/main.ymlund werden bei jedem Lauf in die.envgeschrieben.
Ausrollen (auf ops, idempotent): cd /root/cluster-knaster && git pull, Adressen auffrischen (Abschnitt 6, Schritt 6), dann in platform/proxmox/ansible:
ansible-playbook playbooks/monitoring.yml– Exporter in den GPU-VMs (ohne Treiber-Rolle, kein Neustart) und Stack im LXC.- Ein Image-Update heißt: Tag im Compose-File ändern, committen, Playbook laufen lassen.
Ziele der GPU-VMs (file_sd) auffrischen
Die GPU-VMs haben DHCP-Adressen (D5). platform/proxmox/scripts/monitoring-targets.py schreibt aus tofu output -json gpu_vms und der Registry node.json und gpu.json (Labels instance = VM-Name, pve_node, vmid, slot, slots). Nach jedem VM-Neustart:
cd /root/cluster-knaster/platform/proxmox/tofu && . /root/.config/knaster/tofu.env && bash ../scripts/refresh-vm-access.sh
cd ../ansible && ansible-playbook playbooks/monitoring-targets.yml
Prometheus liest die Dateien in /opt/knaster/infra/file_sd selbst neu, ein Neustart ist nicht nötig.
Exporter in den GPU-VMs: prometheus-node-exporter (Port 9100, Ubuntu-Paket, liest /var/lib/node_exporter/textfile mit den Xid-Zählern) und nvidia_gpu_exporter (Port 9835, nvidia-smi; DCGM unterstützt Maxwell nicht). ufw-Regeln mit Kommentar knaster-monitoring erlauben beide Ports aus 192.168.100.0/24; ufw selbst wird von der Rolle nicht ein- oder ausgeschaltet.
Alerts: Alertmanager meldet an den Router (/v1/healer/alertmanager, Healer im Dry-Run). Der Receiver für n8n knaster-notify ist in deploy/alertmanager/alertmanager.yml nur vorbereitet (auskommentiert). Test: docker exec knaster-infra-alertmanager-1 amtool --alertmanager.url=http://localhost:9093 alert add test severity=warning und … alert query.
Dashboards (Ordner knaster, Startseite „knaster – Übersicht“): Proxmox via Prometheus (grafana.com 10347), Node Exporter Full (1860), Nvidia GPU Metrics (14574), knaster – Übersicht (eigenes).
Achtung HA-Umzug und ZFS-Seiten-Cache (gefunden 12.10.2026 bei der HA-Probe)
Nach zfs receive (Replikation) liefert ein Knoten für Dateien, die dort früher per mmap geöffnet waren, weiter den alten Inhalt aus seinem Seiten-Cache (ZFS 2.4.4, Kernel 7.0.14; Beleg auf pve44: zfs diff <snap> leer, written 0, md5 der Datei trotzdem ungleich der im Snapshot). Folge beim ersten Umzug nach pve48: dockerd las veraltete bbolt-Datenbanken, brach mit panic: invalid freelist page ab, danach fehlten Netzwerk und Volume-Labels. Betroffen ist jeder replizierte LXC mit mmap-Nutzern (Docker, Prometheus-TSDB, später grp-test), sobald er auf einen Knoten zurückkehrt, auf dem er schon lief.
- Schutz im Container: Dienst
knaster-drop-stale-cache.service(Rolleinfra-stack) verwirft vor containerd/docker perposix_fadvise(DONTNEED)den Cache aller Dateien des Containers. Protokoll:journalctl -u knaster-drop-stale-cache -b(zeigt geänderte Datenbank-Prüfsummen). - Eine Lösung auf den Knoten (OpenZFS-Fehler melden bzw. Update, Hookscript) entscheidet der Nutzer.
Wiederherstellung, falls Docker nach einem Umzug nicht startet (im LXC, nichts löschen):
systemctl stop docker containerd;journalctl -u docker -b | grep -A12 paniczeigt die betroffene Datenbank (z. B.buildkit/cache.db).- Die defekte Datenbank bzw. das Verzeichnis beiseiteschieben, z. B.
mv /var/lib/docker/buildkit /var/lib/docker/buildkit.defekt-<datum>. systemctl start docker, danndocker compose -p knaster-infra --env-file /opt/knaster/infra/.env -f /opt/knaster/repo/deploy/compose/infra/docker-compose.yml up -d --force-recreate(Volumes bleiben, keindown -v).- Danach auf ops
ansible-playbook playbooks/monitoring.yml --limit infra.
8. Zugang: Benutzer, Rollen, 2FA, Token (Phase 4.1/4.2)
Stand 13.10.2026, Quelle sites/knaster/proxmox.yaml (access), ausgerollt mit playbooks/cluster.yml (Rolle pve-cluster).
| Konto | Zweck | Rechte | Geheimnis liegt |
|---|---|---|---|
r.rapp@pve |
persönlicher Admin (Weboberfläche) | Gruppe admins = Administrator auf / |
Passwort PVE_ADMIN_R_RAPP_PASS in it/proxmox/.env; Passwort, TOTP und Recovery-Keys in Password Depot (Datei tfa-r.rapp.txt am 13.10. gelöscht) |
root@pam |
Notfallzugang, SSH-Schlüssel, Ansible | alles | Passwörter PVExx_PASS in .env, Schlüssel keys/id_ed25519_pve |
tofu@pve!ops |
OpenTofu auf ops | VM-, Storage-, Mapping-, Pool-Rechte | ops /root/.config/knaster/tofu.env |
monitoring@pve!prom |
pve-exporter | PVEAuditor | ops /root/.config/knaster/pve-exporter.env, Kopie in infra |
healer@pve!knaster |
Healer (SPEC-healer) | Rolle KnasterHealer (VM.PowerMgmt, VM.Audit) nur auf /pool/gpu |
ops /root/.config/knaster/healer.env |
- Anmeldung Weboberfläche: Benutzer
r.rapp, Realm „Proxmox VE authentication server“, danach TOTP-Code. Die Recovery-Keys gelten je einmal. - TOTP: liegt in Password Depot (Feld „Einmalpasswort / 2FA“). Für neue Konten schreibt
pve-admin-user.sheine Dateitfa-<name>.txt; Secret und Recovery-Keys daraus in Password Depot übernehmen und die Datei löschen. - Anmeldung und Vertretung:
docs/ANMELDUNG.md(auch Browser-Falle: Bitwarden-Leiste blockiert den TOTP-Dialog, Inkognito oder Domain ausschließen). - Neues Admin-Konto: Name in
access.admin_userseintragen,playbooks/cluster.ymlauf ops, dann vom Laptopplatform/proxmox/scripts/pve-admin-user.sh <name>(setzt Passwort, TOTP, Recovery-Keys; idempotent). - 2FA für root@pam ist bewusst nicht gesetzt: root bleibt Notfallzugang und läuft über SSH-Schlüssel. Wenn gewünscht, gleiches Vorgehen über
pvesh create /access/tfa/root@pam– vorher den Code in einer App haben, sonst sperrt man sich aus der Weboberfläche aus (SSH bleibt). - Token rotieren:
pveum user token remove <user> <token>, Datei auf ops löschen, Playbook erneut (Healer) bzw. Token neu anlegen und Datei schreiben (tofu, monitoring). - Verloren gegangenes TOTP:
pvesh get /access/tfa/<user>listet die Einträge,pvesh delete /access/tfa/<user>/<id>entfernt sie, danach das Skript erneut.
9. Benachrichtigungen (Phase 4.3)
Ziel knaster-mail (Sendmail an ki@mygodel.de, aus access.mail_to), Matcher knaster-alles ohne Filter (Backup, Fencing, Replikation, Paket-Updates), default-matcher abgeschaltet (sonst doppelt). Postfix auf den Knoten liefert direkt an die MX von mygodel.de (13.10. getestet: 250 … Queued mail for delivery). Kein SMTP-Relay, keine Zugangsdaten.
- Test:
pvesh create /cluster/notifications/targets/knaster-mail/testauf einem Knoten, Zustellung im Journal:journalctl -u postfix --since -10min | grep status=. - Landet die Mail im Spam: Absender
root@pveXX.buero-godel.localhat kein SPF. Dann in Exchange Online eine Transportregel oder einen Connector für die Knoten-IPs anlegen. - Empfänger ändern:
access.mail_toin der Site-Datei, dannpvesh set /cluster/notifications/endpoints/sendmail/knaster-mail --mailto <adresse>(das Playbook legt nur an, es ändert bestehende Ziele nicht).
10. Firewall (Phase 4.4)
Datacenter-Firewall aktiv auf allen Knoten (/etc/pve/firewall/cluster.fw, Vorlage roles/pve-cluster/templates/cluster.fw.j2). Eingehend DROP, ausgehend ACCEPT.
- IPSET
admin: die fünf Knoten, Admin-Laptop.151(WLAN) und.181(USB-LAN im Dock), appsrv08.29, ops.173, infra.188. Nur diese erreichen 22, 8006, 3128, 5900–5999 und 60000–60050. Alle anderen Adressen im LAN bekommen auf diesen Ports DROP, Ping aus dem LAN geht. Corosync zwischen den Knoten erlaubt Proxmox selbst. - Warum eigene Regeln statt IPSET
management: Proxmox ergänztmanagementimmer um das lokale Netz (local_network, hier das ganze /24). Eine Einschränkung auf einzelne Adressen wirkt deshalb nur mit ACCEPT für+adminund anschließendem DROP für das /24 (13.10. geprüft: aus einer GPU-VM sind 22 und 8006 zu, vom Laptop und aus infra offen). - DHCP-Risiko (D5): Seit 14.10. haben ops (.173) und infra (.188) feste Adressen (infra über
containers.infra.ipin der Site-Datei und tofu, ops perpct set 100 -net0 …ip=…auf pve46; DNS .120, Suchdomäne buero-godel.local). Am DC sind sie noch nicht reserviert, der Support soll die Reservierungen nachziehen (Task 0.2). Seit 19.10. hat der Laptop Reservierungen (WLAN .151, Dock .181), ebenso pve44 und pve52. Für infra, pve46 und pve48 ist laut DC derzeit keine Reservierung möglich; sie sind statisch eingestellt, das Restrisiko ist eine doppelt vergebene Adresse. 14.10. passiert: Laptop kam per Dock mit .181 und war ausgesperrt, Rückweg über ops hat funktioniert. Wechselt eine Adresse, ist diese Quelle ausgesperrt. Rückweg: von einer noch zugelassenen Adresse (z. B.ssh ops, dannssh pve44) die Adresse insites/knaster/proxmox.yamländern und das Playbook laufen lassen, oder direktcluster.fwbearbeiten. Letzter Rückweg: Konsole am Knoten, dortpve-firewall stopbzw.enable: 0incluster.fw. - Totmannschalter: Das Playbook stellt bei jeder Änderung einen Timer (
knaster-fw-totmann, 600 s), derenable: 0schreibt, und hebt ihn erst nach erfolgreicher Prüfung (SSH und 8006 zu allen Knoten von ops aus) wieder auf. Bricht der Lauf ab, geht die Firewall von selbst wieder aus. - Neue Verwaltungsquelle (z. B. zweiter Laptop): Eintrag unter
firewall.management, Playbook laufen lassen. - Gast-Firewalls (VM/LXC) sind nicht aktiviert; die GPU-VMs schützen ihre Ports mit ufw (Abschnitt 7).
11. Zertifikat der Weboberfläche (Phase 4.6)
Die Knotenzertifikate stammen von der Cluster-CA (/etc/pve/pve-root-ca.pem, gültig bis 2036) und enthalten die IP-Adresse als SAN. Es reicht, die CA einmal auf dem Laptop als vertrauenswürdig einzutragen, dann sind https://192.168.100.2xx:8006 für alle fünf Knoten ohne Warnung erreichbar.
- Kopie der CA:
it/proxmox/pve-root-ca.pem(SHA-256A2:71:C0:AB:…:77:3E, zum Abgleichopenssl x509 -in … -noout -fingerprint -sha256). - Import ohne Adminrechte (Benutzerspeicher, Windows fragt einmal nach):
certutil -user -addstore Root C:\Users\r.rapp\it\proxmox\pve-root-ca.pem. Danach Browser neu starten. - Kein ACME/Let's Encrypt: die Knoten haben keine öffentlichen Namen (IP-Regel, kein DNS).
12. Netzwerk-Prüfung (Stand 13.10.2026)
| Knoten | NIC | Treiber | Link | Bridge |
|---|---|---|---|---|
| pve44, pve46, pve48, pve52 | Intel onboard nic0 |
e1000e |
1 GBit/s | vmbr0 → nic0, kein VLAN-aware |
| pve61 | USB-NIC im Dock enx3ce1a1c0839d |
r8152 |
1 GBit/s | vmbr0 → USB-NIC, ein Link-Reset seit Start |
- Keine
e1000e-Hänger („Detected Hardware Unit Hang“) im Kernel-Log. Sollten sie auftreten:ethtool -K nic0 tso off gso offals bekannter Ausweg, dann in/etc/network/interfacesfesthalten. - VLAN: nicht aktiviert (Global Constraint „vorerst kein VLAN“). Wenn nötig:
bridge-vlan-aware yesundbridge-vids 2-4094aufvmbr0,ifreload -a; auf pve61 nur vor Ort (USB-NIC). - Eine zweite NIC für ein getrenntes Corosync- oder Migrationsnetz gibt es auf keinem Knoten. Migration läuft
secureüber das LAN. - Feste Adressen: Knoten sind statisch, Gäste und Laptop per DHCP (D5 offen, Task 0.2). Erst mit Reservierungen ist die Firewall-Liste dauerhaft stabil.
13. Testvorgehen
platform/proxmox/scripts/healthcheck.sh (Laptop oder ops, nur lesend) prüft in einem Lauf: Quorum und Stimmen, HA-Dienste, Replikation, Firewall aktiv und Regel +admin, Matcher, Benutzer und 2FA; je Knoten Kernel, fehlgeschlagene Dienste, Knoten-Firewall, NTP, vmbr0, Platz auf /, tank, Zertifikatslaufzeit, GPU-Bindung an vfio-pci, NIC-Hänger, Weboberfläche; dazu den Negativtest aus einer GPU-VM. Ausgabe OK/FEHLER je Prüfung, Exit 1 bei Fehlern.
Wann laufen lassen:
- Nach jedem Playbook-Lauf gegen die Knoten (
site.yml,cluster.yml) und nach jedem Neustart (Abschnitt 6, Schritt 5). - Vor einer Änderung an Firewall, Benutzern oder Netzwerk als Vergleichsbasis.
- Wöchentlich als Routine; Grafana (Abschnitt 7) deckt den Rest kontinuierlich ab.
Manuelle Ergänzungen, die das Skript nicht abdeckt: Anmeldung mit r.rapp@pve und TOTP in der Weboberfläche, Testmail (Abschnitt 9), Dock-Test an pve61 (Task 1.3, vor Ort), Wartungsmodus-Probe (Abschnitt 6).
14. Kubernetes (k3s) und Portainer (D6, seit 15.10.2026)
Die GPU-VMs bilden mit der Dienst-VM k3s einen k3s-Cluster (v1.36.5+k3s1). Steuerung auf k3s (VM 110 auf pve48, tank, HA mit Replikation nach pve52 und pve44, 2 Kerne, 3 GB), Agents gpu-pve44/46/48/52. Docker bleibt in den VMs für noch nicht umgezogene Compose-Stacks (llama.cpp auf pve48, Exporter).
| Was | Wo |
|---|---|
| Server-Adresse | per DHCP (heute 192.168.100.124, MAC bc:24:11:a5:d5:52); Agents nutzen den Namen k3s.knaster aus /etc/hosts (Rolle k3s-agent). Ändert sich die Adresse: refresh-vm-access.sh, dann playbooks/k3s.yml |
| Token und kubeconfig | nur auf ops: /root/.config/knaster/k3s.env, /root/.kube/config; kubectl liegt auf ops |
| 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) |
| GPU in Pods | runtimeClassName: nvidia + resources.limits: {nvidia.com/gpu: 1}; 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_mbin 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 opstofu apply(startet nicht automatisch neu,reboot_after_update = false), dann je Knotenqm reboot <vmid>nacheinander undkubectl get nodeabwarten. Knapp wird es nur im HA-Fall, wenn infra und k3s gleichzeitig auf denselben Ersatzknoten ziehen. - Prüfen: auf ops
kubectl get nodes(fünf Knoten Ready),kubectl get pods -A,kubectl -n nex get pods(nex-stt, nex-tts auf gpu-pve52). - NEX-Sprachdienste laufen seit 15.10. als Deployments im Namespace
nexmit Host-Netz, Ports 8178/8179 auf der VM-Adresse wie zuvor; ufw der VM gilt weiter (nur appsrv08). Umzugstest 15.10.: TTS → STT Rundlauf liefert den Text exakt, M4000 belegt, Compose-Stack ist angehalten (Rückweg:kubectl -n nex delete deploy nex-stt nex-tts, dann in der VMdocker compose -f /opt/nex-speech/docker-compose.yml start).playbooks/nex-speech.ymlbricht deshalb ab, außer mit-e nex_speech_compose=true. - NEX-Websuche (SearXNG) läuft seit 15.10. zusätzlich in k3s (Namespace
nex, NodePort 30880 auf jeder Knoten-Adresse,playbooks/nex-searxng-k3s.yml, Einstellungen = Kopie aus dem nex-Repodeploy/nex/searxng/settings.yml). Der Dienst auf appsrv08 läuft parallel weiter, bis die Hermes-Agenten dort aufSEARXNG_URL=http://<Knoten-IP>:30880umgestellt sind (nex-Adminonboarding), danach den Dienstsearxngim Portainer-Stacknexentfernen. - 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 Volumeportainer_datavon appsrv08 (Portainer EE 2.45.1) übernommen, mit dem offiziellen Werkzeugportainer-ee --rollback-to-ceauf 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 ausit/.hermes.envfunktioniert unverändert. Sicherung/root/.config/knaster/portainer_data.tgzauf 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ürportainer_agent(2.45.1, nur192.168.100.29:9001), den ein Admin als neue Umgebung „appsrv08“ (Agent) anlegt und fürgodel-deployerfreigibt. Die Kubernetes-Umgebung (Nr. 5, Agent:30778) bleibt. Noch auf appsrv08: Portainer EE (:9443) läuft parallel weiter, nginx leitetportainer.mygodel.dedorthin; Umstellung =proxy_passin/var/docker/nginx/etc/nginx/conf.d/portainer.confaufhttps://192.168.100.124:30779,nginx -t, Reload (RunbookIT 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.mdim nex-Repo): Neue Hermes-Agenten entstehen als Deployment im Namespacenex, angelegt von nex-admin auf appsrv08 über die Kubernetes-API (playbooks/nex-k3s.yml: ServiceAccountnex-adminmit Role nur für diesen Namespace, Token auf ops/root/.config/knaster/nex-admin-k8s.token, Pull-Secretgitea-registryaus/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 bleibenhttps://192.168.100.29:<port>/: Traefik auf appsrv08 leitet an den NodePort<port>+20000weiter. Agenten-Volumes liegen auflocal-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 auflocal-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 Secretrustdesk-keys), der Public Key der ClientsBPhsgjAI8yicpNRA3YsnBzfx78JUuNglrYZSZANVCUY=bleibt gültig. hbbs nennt den Clients als Relay die Adresserustdesk_public_host(Standard: k3s-VM, Variable im Playbook). Umstellung der Clients steht aus: sie tragen heute192.168.100.29als 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-Stacksrustdesk-updater(SERVER_HOST). Bis dahin läuft der Stackrustdeskauf appsrv08 weiter. - 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 reichtimage: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_versioninroles/k3s-server/defaultsundroles/k3s-agent/defaultsanheben,playbooks/k3s.yml; erst Server, dann Agents (so läuft das Playbook). Kubernetes-Versionen immer nur eine Minor-Stufe je Schritt. - Stromausfall: VM 110 startet automatisch (onboot, HA). Agents verbinden sich neu, Pods starten mit den Knoten. Sollte
k3sauf einen anderen Knoten umziehen, bleibt die Adresse (gleiche MAC), sobald die DHCP-Reservierung am DC steht.