Entrada

kagent + Agent Substrate: agentes en producción con sandboxes que duermen

kagent + Agent Substrate: agentes en producción con sandboxes que duermen

El agente que pasa el 95% del día esperando

En mi último post sobre kagent les conté cómo desplegar agentes de IA como recursos nativos de Kubernetes. En ese momento Agent Substrate aún no estaba disponible; hoy sí, y cambia por completo la forma en que kagent ejecuta los agentes.

Un agente pasa más del 95% de su tiempo esperando al LLM o a un humano. En el modelo “un agente, un Pod”, ese Pod reserva CPU y memoria 24/7. Con cientos de agentes en sandbox, el billing cloud crece y sigue creciendo.

Agent Substrate: la plomería

Agent Substrate es un runtime y scheduler open source que corre sobre Kubernetes, fundado por Google y mantenido junto con Solo.io (repo). Cada sesión de agente es un Actor, y un pool chico de Pods precalentados, los Workers, ejecuta solo los Actors que están trabajando. Cuando un Actor queda ocioso, Substrate guarda su RAM y su filesystem en S3 o GCS y libera el Worker; con la siguiente petición lo restaura en cualquier Worker libre.

  • ate-api-server: scheduler y ciclo de vida de los Actors.
  • atenet-router: DNS + proxy L7 que reanuda el Actor y le enruta la petición.
  • atenet-egress: salida default-deny que inyecta las credenciales.
  • atelet: DaemonSet que sube y baja los snapshots.

El proyecto anuncia hasta 1.000 Actors por Worker y una demo de ~250 Actors sobre 8 Pods. Son objetivos de diseño; todavía no hay benchmarks publicados.

kagent 1.0: qué cambió

kagent 1.0 deja atrás los Deployments y ejecuta todas las sesiones sobre Substrate (The future of kagent). La migración desde 0.x es manual. El modelo nuevo vive en el grupo api.kagent.dev (core concepts):

RecursoQué defineDónde vive
HarnessCómo se ejecuta: motor, imagen, WorkerPool y bucketCRD
AgentTemplateQué hace: modelo, prompt, tools MCP y skillsCRD
AgentUne un AgentTemplate con un HarnessCRD
SessionUna conversación en cursoPostgreSQL
ActorEl proceso en sandbox que la ejecutaSubstrate

El controller compila cada Agent en un ActorTemplate inmutable, y cada Session queda fijada a esa revisión, igual que un ReplicaSet con su pod-template-hash.

Arquitectura: cómo encajan las piezas

kagent es la capa con la que hablan desarrolladores y plataformas; Substrate decide dónde corre cada agente y cuánto cuesta mantenerlo.

Arquitectura de kagent + Agent Substrate en tres capas sobre Kubernetes

Solo los Actors con un turno en curso ocupan un Worker. El resto duerme en el object store hasta que llega la siguiente petición y el router lo reanuda.

Manos a la obra con kind - dejamos EKS para la próxima ;)

Para probarlo no hace falta una nube: alcanza con kind. Sigo la guía oficial de kagent 1.x y algunos consejos de la guía con kind del equipo de kagent. Ojo: kagent 1.0 está en RC y Substrate es pre-1.0, así que esto es para laboratorio.

Requisitos:

  • Unos 8 vCPU y 16 GB de RAM para Docker. Yo lo probé en una Mac con Apple Silicon y Docker Desktop, y funcionó con un fix de una línea que explico en los retos reales.
  • kind v0.32 o superior y la imagen kindest/node:v1.37.0, porque Substrate usa las APIs de Pod Certificates de Kubernetes 1.37.
  • Una API key gratuita de Google AI Studio (aistudio.google.com), sin tarjeta de crédito. Vamos a usar Gemini 3.8 Flash, el Flash más reciente, que entra en el free tier.
1
2
3
4
5
6
7
kind create cluster --name kagent --image kindest/node:v1.37.0
kubectl api-resources --api-group=certificates.k8s.io  # deben aparecer podcertificaterequests y clustertrustbundles

curl https://raw.githubusercontent.com/kagent-dev/kagent/refs/heads/main/scripts/get-kagent | bash -s -- --version v1.0.0-rc1
export GOOGLE_API_KEY="<tu-api-key-de-ai-studio>"
kagent install --namespace kagent   # instala Substrate, PostgreSQL de desarrollo y kagent
kubectl get workerpools -n kagent  # kagent-default debe tener READY=1

Después creamos un ModelConfig que apunte a Gemini, como indica la documentación de kagent para Gemini:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kubectl create secret generic kagent-gemini -n kagent --from-literal GOOGLE_API_KEY=$GOOGLE_API_KEY

kubectl apply -f - <<EOF
apiVersion: api.kagent.dev/v1alpha3
kind: ModelConfig
metadata:
  name: gemini-model-config
  namespace: kagent
spec:
  apiKeySecret: kagent-gemini
  apiKeySecretKey: GOOGLE_API_KEY
  model: gemini-3.8-flash
  provider: Gemini
  gemini: {}
EOF

Dos cosas a tener en cuenta del free tier: tiene límites de peticiones por minuto y por día, y Google puede usar esas peticiones para mejorar sus productos, así que no le pasen datos sensibles. Si gemini-3.8-flash responde que está saturado o se agota la cuota, cambien a gemini-3.5-flash-lite, que tiene su propio contador.

En kind, los snapshots van al object store que trae el chart de Substrate (RustFS), así que no hay que configurar ningún bucket. El primer agente son tres recursos:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
apiVersion: api.kagent.dev/v1alpha3
kind: Harness
metadata: { name: sre-harness, namespace: kagent }
spec:
  kagent: {}
  workload:
    image: ghcr.io/kagent-dev/kagent/golang-adk@sha256:d20d411759d7bb549f00b7d6e8d669b91694aeb57dce847dcd2cbb68aa0d45f3
    args: ["-filepath", "/data/config"]   # fix: ver "Los retos reales"
  substrate:
    workerPoolRef: { name: kagent-default }
    snapshotPolicy: { location: s3://ate-snapshots/kagent/ }
---
apiVersion: api.kagent.dev/v1alpha3
kind: AgentTemplate
metadata: { name: sre-assistant, namespace: kagent }
spec:
  modelConfig: { name: gemini-model-config }
  systemPrompt: Eres un SRE conciso. Responde con comandos concretos.
---
apiVersion: api.kagent.dev/v1alpha3
kind: Agent
metadata: { name: sre-agent, namespace: kagent }
spec:
  template: { ref: { name: sre-assistant } }
  harnessRef: { name: sre-harness }
1
2
3
kubectl apply -f sre-agent.yaml
kubectl get agents.api.kagent.dev -n kagent   # esperen a que sre-agent esté Ready (~1 min mientras crea el golden snapshot)
kubectl port-forward -n kagent service/kagent-ui 8082:8080

A partir de acá todo pasa en la UI de kagent, en http://localhost:8082.

En Agents, la pantalla resume el modelo de 1.0: un AgentTemplate (qué hace) más un Harness (dónde y cómo corre) forman un Agent, y cada chat es una Session que corre como un Actor de Substrate. En la pestaña Harnesses aparece nuestro sre-harness con el runtime kagent y la imagen fijada por digest.

UI de kagent: la página Agents con el resumen AgentTemplate + Harness → Agent → Session y la pestaña Harnesses mostrando sre-harness

En Substrate está la parte que más me gusta. Con el agente ya creado, el golden snapshot está listo (Templates ready 1/1), pero Actors running 0/1 y Workers busy 0/1: el agente existe y no ocupa nada. El pool kagent-default corre la imagen ateworker-gvisor:v1.0.0-rc1, y el template sre-agent aparece en fase Ready con su golden snapshot.

Vista Substrate de kagent: 1 worker pool, Templates ready 1/1, Actors running 0/1 y Workers busy 0/1

Una forma sencilla de probarlo:

  1. Abran sre-agent y pregunten: “How do I troubleshoot a pod in CrashLoopBackOff?”.
  2. Mientras responde, refresquen Substrate: Workers busy pasa a 1/1. Al terminar el turno vuelve a 0/1, porque el Actor quedó suspendido en el object store.
  3. Pregunten: “What if the pod is in another namespace?”. La respuesta llega con el contexto intacto, porque Substrate restauró el Actor desde su snapshot.
  4. Bonus: el ícono de guardar junto a la caja de mensajes crea un checkpoint, que la UI llama Snapshot. Desde esa marca pueden hacer Fork y arrancar una conversación nueva exactamente desde ese punto.

Dos consejos de la guía con kind: hagan el laboratorio de una sola vez, porque los certificados internos pueden expirar si el clúster queda inactivo cerca de 24 horas, y bórrenlo al terminar con kind delete cluster --name kagent.

Cuando quieran pasar a EKS, los cambios principales son un clúster 1.37, snapshots en S3 con EKS Pod Identity y PostgreSQL en RDS.

Los retos reales

  • Deriva de versiones: las guías mezclan AgentHarness v1alpha2 con Harness v1alpha3 y charts de Substrate de 0.0.8 a 0.2.0. Incluso el apiVersion del ModelConfig cambió: la documentación dice kagent.dev/v1alpha3, pero en 1.0.0-rc1 es api.kagent.dev/v1alpha3. Regla de oro: no actualicen Substrate por su cuenta; usen la versión que fija cada release de kagent (versiones) y verifiquen con kubectl api-resources.
  • El egress hace MITM del TLS: atenet-egress termina HTTPS para filtrar por hostname. Esto rompe el certificate pinning y bloquea UDP, HTTP/3 y SSH. Los rechazos solo aparecen en kubectl logs -n ate-system deploy/atenet-egress -c agentgateway.
  • Credenciales: el gateway usa la identidad SPIFFE del Actor y reemplaza un header placeholder por la API key real. Si la petición no trae el placeholder, sale sin credencial y el LLM responde 401.
  • EKS privados: los nodos descargan los assets de gVisor desde una URL pública de GCS; sin salida a Internet hay que alojar una copia.

El que me pasó a mí: el agente nunca despertaba. El golden snapshot fallaba con GoldenActorCrashed, porque el wakeup probe (/readyz en el puerto 8081) daba “connection refused” a los 30 segundos y Substrate reintentaba en loop. Los logs del atelet mostraban arm64 y gVisor, así que primero sospeché de mi Mac. Pero no era eso.

La pista real estaba en los logs del Worker (kagent-default-*):

1
materialize agent config in /config: ... mkdir /config: permission denied

El binario /app corre como el usuario no root 65532 e intenta crear /config en la raíz del filesystem, que pertenece a root. Crashea antes de levantar el servidor HTTP, así que el probe nunca recibe respuesta. Con /app --help vi que acepta -filepath, y lo apunté a /data, el durable dir que Substrate monta y que sí es del usuario 65532:

1
2
3
workload:
  image: ghcr.io/kagent-dev/kagent/golang-adk@sha256:d20d41...
  args: ["-filepath", "/data/config"]

Después de borrar y recrear el agente para forzar un nuevo golden snapshot, arrancó a la primera. La lección como SRE: antes de culpar a la plataforma, lean los logs del Worker, no solo los del control plane.

Conclusión

kagent pone la experiencia de desarrollo y Substrate la plomería. Con kind lo prueban en una tarde, y con EKS 1.37 ya disponible el salto a AWS es corto. las posibilidades son muchas, pero si hay algo claro aqui es que este tipo de herramientas estan definiendo nuevos estandares sobre coom correr agentes de una forma segura y eficiente.

Definitivamente el futuro de los workloads agénticos está en Kubernetes.

Referencias

Esta entrada está licenciada bajo CC BY 4.0 por el autor.