Rebuild profile router as secure recoverable v2
This commit is contained in:
+27
-1
@@ -11,7 +11,7 @@ in diesem Repository oder im Modellmanifest beschrieben sind.
|
||||
|
||||
| Komponente | Port | Ausführung | Aufgabe |
|
||||
|---|---:|---|---|
|
||||
| AI Profile Router | 8081 | systemd, unprivilegiert empfohlen | zentrale Client-API und Orchestrierung |
|
||||
| AI Profile Router | 8081 | systemd, gehärtet | zentrale Client-API und Orchestrierung |
|
||||
| llama.cpp | 8080 | systemd | Textmodell, Tool Calling und MCP |
|
||||
| Whisper | 8084, nur localhost | systemd | Speech-to-Text |
|
||||
| XTTS | 8085, nur localhost | systemd | Text-to-Speech |
|
||||
@@ -29,11 +29,20 @@ in diesem Repository oder im Modellmanifest beschrieben sind.
|
||||
4. Der Router wartet auf Modellname und erwartete Kontextgröße.
|
||||
5. Erst dann wird die Anfrage an Port 8080 weitergeleitet.
|
||||
|
||||
Profilwahl und Weiterleitung bilden dabei eine atomare Modell-Lease. Ein
|
||||
zweiter Request kann das Profil nicht mehr zwischen Auswahl und Inferenz
|
||||
wechseln. Laufende Requests werden vor einem GPU-Hotswap vollständig beendet;
|
||||
bei Überschreiten des Drain-Timeouts wird der Wechsel abgebrochen, nicht der
|
||||
Chat.
|
||||
|
||||
## Profilprinzip
|
||||
|
||||
Die Profile sind vollständige systemd-Overrides. Ein Profilwechsel kopiert die
|
||||
gewählte Datei atomar auf `override.conf`, lädt systemd neu und startet genau
|
||||
einen llama.cpp-Dienst neu. Es gibt niemals mehrere Textmodelle gleichzeitig.
|
||||
Das unabhängige Register `/etc/mike-ai/router-profiles.json` definiert Kontext
|
||||
und erwarteten Modellalias. Readiness gilt nur, wenn beides exakt passt; eine
|
||||
abweichende oder fehlende Registry verhindert den Start.
|
||||
|
||||
## GPU-Hotswap
|
||||
|
||||
@@ -47,6 +56,23 @@ Vision und Bildgenerierung teilen sich die RTX mit dem Textmodell. Der Router:
|
||||
6. stellt das ursprüngliche Textprofil wieder her,
|
||||
7. prüft Modell und Kontext vor der Freigabe.
|
||||
|
||||
Der zuletzt stabile Zustand und temporäre Worker-PIDs werden atomar unter
|
||||
`/var/lib/mike-ai-profile-router/state.json` festgehalten. Beim Routerstart
|
||||
werden ausschließlich dort erfasste Prozesse nach zusätzlicher
|
||||
Kommandozeilenprüfung beendet und das letzte Profil wiederhergestellt.
|
||||
|
||||
## Vertrauensgrenzen
|
||||
|
||||
- Port 8081 verlangt einen eigenen API-Key; nur `/health` und `/ready` sind
|
||||
absichtlich anonym und enthalten keine privaten Daten.
|
||||
- Der Client-Key wird vor dem lokalen Upstream entfernt.
|
||||
- Bild-Uploads sind begrenzt. Remote-Bild-URLs sind standardmäßig aus, damit
|
||||
der Vision-Pfad nicht als Zugriff auf Intranet oder Metadatenendpunkte dient.
|
||||
- Maximal 16 Requests werden gleichzeitig bearbeitet; weitere erhalten 429.
|
||||
- Der Dienst benötigt derzeit wegen systemd-Profilwechsel und GPU-Hotswap noch
|
||||
Root-Rechte. Die systemd-Sandbox begrenzt diese, ersetzt aber keine künftige
|
||||
Aufteilung in unprivilegierten Proxy und eng begrenzten Root-Helper.
|
||||
|
||||
## Verzeichnislayout auf dem Zielhost
|
||||
|
||||
```text
|
||||
|
||||
@@ -31,6 +31,10 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
||||
|
||||
## Phase C – Router
|
||||
|
||||
- [ ] Start ohne API-Key schlägt bewusst fehl
|
||||
- [ ] `/health` bleibt bei Hotswap 200 und `/ready` wird vorübergehend 503
|
||||
- [ ] geschützte Endpunkte liefern ohne Key 401
|
||||
- [ ] Router-Key erscheint weder im Upstream noch im Journal
|
||||
- [ ] `/status` meldet den richtigen Upstream
|
||||
- [ ] `/v1/models` liefert drei virtuelle Modelle
|
||||
- [ ] `/fast`, `/medium` und `/long` wechseln zuverlässig
|
||||
@@ -40,6 +44,8 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
||||
- [ ] Tool Calls funktionieren
|
||||
- [ ] Fehler sind OpenAI-kompatibel
|
||||
- [ ] ein abgebrochener Client hinterlässt keinen blockierten Job
|
||||
- [ ] erzwungener Routerabbruch wird aus Zustandsdatei sauber rekonstruiert
|
||||
- [ ] fehlende/falsche Profilregistry verhindert falsche Readiness
|
||||
|
||||
## Phase D – Web und MCP
|
||||
|
||||
@@ -58,6 +64,7 @@ laufen, sondern alle fachlichen Funktionen geprüft wurden.
|
||||
- [ ] neues Bild löst genau einen Vision-Hotswap aus
|
||||
- [ ] Folgefrage verwendet Cache und keinen zweiten Hotswap
|
||||
- [ ] Bilddaten werden vor dem Textmodell sanitisiert
|
||||
- [ ] Remote-/private Bild-URL wird abgewiesen und übergroße Data-URL blockiert
|
||||
- [ ] Qwen-Profil wird nach Vision wiederhergestellt
|
||||
- [ ] FLUX erzeugt Standard- und High-Bild
|
||||
- [ ] Qwen-Profil wird nach FLUX wiederhergestellt
|
||||
|
||||
@@ -65,6 +65,17 @@ Das bestehende `deploy/install.sh` installiert Router, Vision/Bild-Worker,
|
||||
Whisper und XTTS. Vor produktiver Verwendung müssen Modellpfade in der
|
||||
systemd-Datei gegen das lokale Manifest geprüft werden.
|
||||
|
||||
Der Installer erzeugt `/etc/mike-ai/router-api-key` (0600), installiert das
|
||||
Profilregister und legt die atomare Zustandsablage an. Danach wird der Key
|
||||
einmal manuell in die Secret-Stores der erlaubten Clients übernommen. Er darf
|
||||
nicht im Terminal-Log, in Screenshots oder in Git dokumentiert werden.
|
||||
|
||||
Der Router läuft aktuell als gehärteter Root-Dienst, weil er den
|
||||
llama.cpp-Systemdienst und temporäre GPU-Worker kontrolliert. Das ist eine
|
||||
bewusste Restabweichung. Ein späterer V3-Schritt soll den HTTP-Proxy als eigenen
|
||||
Benutzer ausführen und nur Profil-/Hotswap-Befehle an einen fest
|
||||
parametrisierten Root-Helper delegieren.
|
||||
|
||||
## 8. Websuche
|
||||
|
||||
TinySearch und SearXNG bleiben als einziges Docker-Teilsystem isoliert. Die
|
||||
|
||||
+24
-1
@@ -20,12 +20,19 @@ Clients verbinden sich mit:
|
||||
http://HOST:8081/v1
|
||||
```
|
||||
|
||||
Als API-Key verwenden sie den Inhalt von `/etc/mike-ai/router-api-key` über
|
||||
Bearer-Authentifizierung. Der Key gehört in den Secret-Store des Clients,
|
||||
nicht in Chat, Repository oder URL. Eine Rotation erfolgt atomar durch
|
||||
Ersetzen der Datei und Neustart des Routerdienstes.
|
||||
|
||||
Sie sollen nicht direkt Port 8080 verwenden, weil sie sonst Profilumschaltung,
|
||||
Vision, Bildgenerierung, STT und TTS umgehen.
|
||||
|
||||
## Status
|
||||
|
||||
- `GET /status`: Router, Profil, Upstream, aktive Jobs
|
||||
- `GET /health`: Routerprozess lebt; bleibt bei geplantem Hotswap grün
|
||||
- `GET /ready`: Router und Textmodell sind einsatzbereit
|
||||
- `GET /status`: authentifizierter Detailstatus, Profil, Upstream, aktive Jobs
|
||||
- `GET /v1/models`: virtuelle Modelle
|
||||
- llama.cpp-Metriken: Port 8080, nur im administrativen Netz freigeben
|
||||
- systemd-Journal: nur Metadaten und Fehler prüfen; keine Promptinhalte sammeln
|
||||
@@ -35,6 +42,22 @@ Vision, Bildgenerierung, STT und TTS umgehen.
|
||||
Niemals Build, Quantisierung und Profil gleichzeitig ändern. Immer genau eine
|
||||
Variable ändern und anschließend denselben Benchmark ausführen.
|
||||
|
||||
Profilkontext und Alias werden zusätzlich in
|
||||
`/etc/mike-ai/router-profiles.json` gepflegt. Änderungen an Override und
|
||||
Registry gehören in denselben getesteten Commit; andernfalls verweigert die
|
||||
Readiness bewusst die Freigabe.
|
||||
|
||||
## Fehler- und Recovery-Verhalten
|
||||
|
||||
- Ein Profilwechsel bricht ab, wenn laufende Chats nicht innerhalb des
|
||||
Drain-Timeouts enden. Er beendet niemals absichtlich einen Chat.
|
||||
- Nach einem Routerabsturz wird das letzte stabile Profil aus der atomaren
|
||||
Zustandsdatei rekonstruiert.
|
||||
- `/health = 200`, aber `/ready = 503` bedeutet: Router lebt, Modell ist noch
|
||||
nicht bereit oder wird gerade gewechselt.
|
||||
- `429` bedeutet, dass die Parallelitätsgrenze erreicht ist; der Client soll
|
||||
mit Backoff erneut versuchen.
|
||||
|
||||
## Kapazitätsregeln
|
||||
|
||||
- Systempartition dauerhaft unter 85 Prozent halten.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Router V2 – Migration und Kompatibilität
|
||||
|
||||
## Ergebnis
|
||||
|
||||
V2 behält die OpenAI-kompatible Basis-URL und die virtuellen Modelle
|
||||
`qwen-fast`, `qwen-medium` und `qwen-long`. Bestehende Chat-, Tool-, Audio-,
|
||||
Vision- und Bildpfade bleiben erhalten. Die Änderungen betreffen absichtlich
|
||||
die Stellen, an denen der alte Router unsicher oder nicht deterministisch war.
|
||||
|
||||
## Bewusste Änderungen
|
||||
|
||||
| Alt | V2 |
|
||||
|---|---|
|
||||
| alle LAN-Clients ohne Authentifizierung | API-Key für alle fachlichen Endpunkte |
|
||||
| `GET /fast` schaltet ein Modell | nur noch `POST /fast` (analog medium/long) |
|
||||
| `/health` hängt am Modellzustand | `/health` = Prozess, `/ready` = Textmodell |
|
||||
| Profil durch Textvergleich erkannt | Kontext + Alias aus Profilregister geprüft |
|
||||
| Profilwechsel und Request konnten sich überholen | atomare Modell-Lease |
|
||||
| Drain-Timeout beendete trotzdem das Modell | Wechsel wird sicher abgebrochen |
|
||||
| Workerzustand nur im RAM | atomare Zustandsdatei und Startup-Recovery |
|
||||
| beliebige Bild-URL | Data-URL, Größenlimit; Remote standardmäßig aus |
|
||||
| unbegrenzte Parallelität und Bildablage | Request- und Retention-Limits |
|
||||
| Auth-Header potenziell am Upstream | Router-Credentials werden entfernt |
|
||||
|
||||
## Client-Migration
|
||||
|
||||
1. Router-Key aus `/etc/mike-ai/router-api-key` ohne Anzeige in einen lokalen
|
||||
Secret-Store des Clients übernehmen.
|
||||
2. Basis-URL unverändert auf `http://HOST:8081/v1` lassen.
|
||||
3. Den Key als OpenAI-API-Key/Bearer-Token konfigurieren.
|
||||
4. `GET /v1/models` testen und anschließend einen kurzen Chat über
|
||||
`qwen-fast` senden.
|
||||
5. Automationen, die Profile per GET schalten, auf POST umstellen.
|
||||
6. Überwachung auf `/health` (Liveness) und `/ready` (Readiness) aufteilen.
|
||||
|
||||
## Sicheres Rollout
|
||||
|
||||
V2 wird nicht blind über einen laufenden Router kopiert:
|
||||
|
||||
1. Repository-Commit und aktuelle produktive Konfiguration sichern.
|
||||
2. Profilregister gegen alle drei systemd-Overrides prüfen.
|
||||
3. API-Key erzeugen und Clients vorbereiten.
|
||||
4. Router installieren und zuerst lokal mit Key prüfen.
|
||||
5. Fast, Medium und Long jeweils einmal schalten und Alias/Kontext prüfen.
|
||||
6. Streaming und einen Tool Call testen.
|
||||
7. Erst danach normale Clients auf V2 freigeben.
|
||||
|
||||
Ein Rollback stellt Routerdateien und Unit aus dem Installationsbackup wieder
|
||||
her. Der neu erzeugte API-Key und die Zustandsdatei enthalten keine
|
||||
Modelldateien oder Chatdaten.
|
||||
|
||||
## Verbleibender Architekturpunkt
|
||||
|
||||
Der Routerprozess läuft derzeit als root, weil er den systemweiten llama.cpp-
|
||||
Dienst und temporäre GPU-Worker steuert. Die Unit ist stark gehärtet, dennoch
|
||||
ist das nicht das langfristige Ideal. V3 soll HTTP/API und privilegierte
|
||||
Orchestrierung trennen: unprivilegierter Proxy plus kleiner Root-Helper mit
|
||||
festen, nicht frei parametrisierbaren Aktionen.
|
||||
@@ -42,6 +42,20 @@ Empfohlene Trennung:
|
||||
- Firewall erlaubt nur bekannte Quellnetze.
|
||||
- Externe Suche erhält nur die tatsächliche Suchanfrage, keine Chat-Historie.
|
||||
|
||||
## Router-Grenze
|
||||
|
||||
- Alle fachlichen Endpunkte verlangen einen mindestens 32 Zeichen langen,
|
||||
zufälligen Router-Key. Der Dienst startet ohne gültigen Key nicht.
|
||||
- `/health` und `/ready` sind die einzigen anonymen Endpunkte und geben nur
|
||||
groben Betriebszustand aus.
|
||||
- Authentifizierungsheader werden niemals an llama.cpp weitergereicht.
|
||||
- Remote-Bild-URLs sind standardmäßig gesperrt. Data-URLs werden auf MIME-Typ,
|
||||
Base64-Gültigkeit und 20 MiB Maximalgröße geprüft.
|
||||
- Die Zahl gleichzeitiger Requests ist begrenzt; große Uploads sind global
|
||||
begrenzt und generierte Bilder werden nach Alter, Anzahl und Größe bereinigt.
|
||||
- Crash-Recovery beendet keine PID nur aufgrund einer Zahl, sondern verlangt
|
||||
zusätzlich einen erwarteten Prozessmarker in `/proc/<pid>/cmdline`.
|
||||
|
||||
## Schreibaktionen
|
||||
|
||||
Jede destruktive oder persistente Aktion verwendet:
|
||||
|
||||
Reference in New Issue
Block a user