Agent Sandbox OSS
Un runtime Kubernetes per agenti AI di lunga durata e ad alto consumo di dati
Perché l’ho fatto
Portare gli agenti in produzione significa scontrarsi subito con tre muri: un processo condiviso non è né sicuro né in grado di garantire QoS, creare un pod su richiesta costa decine di secondi e il guasto di un nodo si porta via lo stato in corso. Questo progetto affronta i tre problemi uno alla volta, in sette lab dove ogni passo risolve solo ciò che il precedente ha fatto emergere.
Cosa fa
Pool caldo: operativi in millisecondi
Un gruppo di pod già avviati resta in attesa: la richiesta ne occupa uno direttamente, saltando scheduling, download dell’immagine e init del container. Sullo stesso percorso, crearlo su richiesta costa 45–90 secondi. La cifra esatta dipende dalla macchina e dalla dimensione del pool; l’endpoint restituisce il valore appena misurato.
Workspace separati dal calcolo
Lo stato dell’utente vive su PVC o su checkpoint remoto: il pod è solo l’esecutore. Si elimina a mano un pod in esecuzione e un pod nuovo rimonta lo stesso workspace e prosegue.
Scheduling in pull
Non è più un allocatore a spingere il lavoro verso un pod scelto: sono i pod a prendere i task dalla coda. Doppio scheduling e prelazione spariscono con esso — niente Lease di K8s, niente Redlock.
Isolamento a runtime
Una RuntimeClass sposta i carichi non affidabili su gVisor / Kata, comprando un confine che non condivide il kernel e pagandolo in tempo di avvio.
Sette lab progressivi
Si parte dal pod singolo ingenuo e ogni passo prima rompe qualcosa e poi introduce il componente: l’intera evoluzione resta nel repository.
Il punto di partenza
Un agente non è una richiesta web: dura a lungo, consuma memoria, scrive file ed esegue codice che un modello ha scritto pochi secondi prima. Messo in un processo condiviso, il primo giorno insegna due cose — un task va in OOM e si porta via gli altri, e un payload malevolo legge tranquillamente un secret montato nel container. L’isolamento non è un’ottimizzazione, è il biglietto d’ingresso.
Ma l’isolamento si fa pagare subito, e ogni pagamento fa emergere il problema successivo. Questo repository è quella catena, messa per iscritto.
Come procedono i sette passi
| Passo | Il muro | La risposta del passo |
|---|---|---|
| 1 Pod singolo | I task si bloccano a vicenda, un OOM li abbatte tutti, il codice malevolo legge i secret | Si fissa la baseline: serve isolamento a livello di container |
| 2 Su richiesta | Il TTI passa da 0,5 s a 45–90 s; CPU dell’APIServer alle stelle, latenza di scrittura su etcd | L’avvio a freddo è fisica, e KubeAPI non può stare sul percorso sincrono |
| 3 Pool caldo | La latenza torna a poche centinaia di ms, al prezzo di pod che girano a vuoto | Si scambia ridondanza per latenza e iniziano i conti sulla capacità |
| 4 Workspace | Un pod che muore si porta via un’analisi a metà | Lo stato passa su PVC / checkpoint; il pod diventa sostituibile |
| 5 Da push a pull | L’allocatore deve gestire prelazione, lock e contese | I worker prendono dalla coda, e in più si ottengono le priorità |
| 6 Isolamento duro | Con kernel condiviso un carico ostile può ancora esaurire il nodo o tentare la fuga | Si passa a gVisor / Kata via RuntimeClass, misurando il costo d’avvio |
| 7 Caos | Sei passi validi singolarmente non è detto reggano insieme | Si uccidono nodi e il primario della coda, si misurano MTTD / MTTR / disconnessioni |
Tre compromessi che vale la pena capire
Il pool caldo non è un conto tecnico. Passare da decine di secondi a poche centinaia di millisecondi è centinaia di volte più veloce, pagato con pod che restano accesi a vuoto. Finito quel passo, la domanda non è più «come lo rendiamo veloce» ma «quanti conviene tenere caldi e come si scalano con il carico»: economia, non tuning.
I pod muoiono, il contesto no. Solo dopo aver estratto il workspace dal pod la prova di guasto significa qualcosa: si elimina un pod in esecuzione, un pod nuovo monta lo stesso workspace e prosegue, e si misurano tempo di ripristino e coerenza dei dati invece del semplice «è sopravvissuto?».
Lo scheduling si risolve non facendolo. Spingere il lavoro richiede sapere chi è libero e difendersi dalla prelazione, e quindi introdurre lock. Quando sono i worker a prendersi i task, quei problemi non vengono risolti: smettono di esistere. I sistemi batch finiscono sempre qui.
Come si verifica
L’ultimo passo rimette insieme tutto e lo rompe di proposito: si tengono centinaia di sessioni attive, si uccide il trenta per cento dei nodi e poi il primario della coda, e si osserva quanto ci mette il sistema ad accorgersi del lavoro fermo (MTTD), quanto impiega un workspace a riagganciarsi a un pod nuovo (MTTR) e quanti utenti hanno davvero visto un errore. Senza questo passo, i primi sei sono corretti solo presi singolarmente.
Stato attuale
In corso. Le interfacce cambiano ancora, nessuna release. Tutto è open source: le issue sul design sono benvenute.