13°
Portada del artículo: Aislar un agente de código con gVisor o Kata: cuánto cuesta frente a Docker, medido
ContenedoresSeguridadAgentesBenchmarks

Aislar un agente de código con gVisor o Kata: cuánto cuesta frente a Docker, medido

Medí cuánto cuesta correr el trabajo de un agente de código aislado en gVisor y en Kata Containers 4.3 (con QEMU y con Cloud Hypervisor) en vez de un contenedor Docker normal. Kata tarda 6 a 7 s en arrancar contra 0,22 s de runc y deja 199 a 302 MiB por contenedor contra 11,5; gVisor arranca en 0,33 s, usa 48,6 MiB y empata con runc en una carga de miles de archivos pequeños.

Efrain Garay 23 de octubre de 2026

Reproduciendo el resumen

Dejo que agentes de código ejecuten comandos en mis máquinas, y lo que más se repite cuando alguien habla de eso es el miedo a que un agente rompa algo fuera de su carpeta. La respuesta habitual es aislarlo más: en vez de un contenedor Docker normal, un sandbox como gVisor, que le pone delante un kernel escrito en espacio de usuario, o Kata Containers, que mete cada contenedor en una máquina virtual liviana con su propio kernel. Quería saber cuánto cuesta eso en tiempo y en memoria con trabajo de agente, en la misma máquina y con los mismos límites.

No probé si se pueden escapar. Eso es otro estudio. Aquí medí solo el precio de la protección.

Con narración: el kernel del host como una plataforma con cuatro compartimentos, uno por sandbox, cada uno construido con lo que el host ve de un contenedor. Memoria en reposo de 11,5 a 302 MiB, una carrera de arranque a velocidad real (0,22 s runc, 7,09 s Kata con QEMU) y 5.000 archivos pequeños donde gVisor empata con runc.Verlo en el visualizador de reels →

Qué medí, y con qué reglas

Antes de la primera corrida dejé escrita una ficha con la pregunta, tres hipótesis y la regla de decisión, y la enmendé por escrito cuatro veces; cada enmienda dice por qué.

  • Máquina: un portátil Lenovo con un Intel Core i5-8250U (4 núcleos, 8 hilos), 11 GiB de RAM y un SSD SATA, con NixOS, kernel Linux 6.18 y KVM.
  • Brazos: Docker 29.8 con su runtime por defecto, runc 1.5.1 (la referencia). gVisor (runsc 20260406.0, el de nixpkgs) con su plataforma por defecto. Kata Containers 4.3.0 con los binarios estáticos oficiales y su configuración por defecto, que usa QEMU 11.0. Y, por una enmienda que explico abajo, el mismo Kata con su configuración oficial de Cloud Hypervisor v54.
  • Límites: todos los contenedores con --cpus 2 --memory 2g --network none.
  • Cargas: cinco, cada una con la misma imagen en los cuatro brazos:
    • Arranque: docker run --rm de una imagen mínima que ejecuta true, cronometrado desde el host. 30 corridas por brazo.
    • Memoria: un contenedor en reposo (sleep 300) y, a los 10 segundos, la suma de PSS de sus procesos en el host. 10 corridas.
    • Replay de comandos de agente: los comandos que ejecutaron agentes reales en otro experimento mío, todavía sin publicar, repetidos en orden dentro de un contenedor nuevo. 10 corridas.
    • Compilación: Lua 5.4.7 completo, make y limpieza. 10 corridas.
    • Muchos archivos pequeños: crear un entorno virtual de Python, instalar JupyterLab desde un índice local sin red y descomprimir un árbol de 5.000 archivos. 10 corridas.
  • Regla: mediana por brazo y razón contra runc, con un intervalo de confianza del 95 % por bootstrap (10.000 remuestreos, semilla 17). «Más lento» si el intervalo excluye 1 y la razón supera 1,10; «empate» solo si el intervalo entero cae entre 0,95 y 1,05.

Arranque: Kata necesita segundos

Arranque de docker run --rm true, a velocidad real (mediana de 30 corridas)
runc0,22 sgVisor0,33 sKata · QEMU7,09 sKata · CLH6,12 s

runc arrancó y terminó el contenedor en 0,22 s; gVisor, en 0,33 s, 1,48 veces más. Kata con QEMU tardó 7,09 s, 31,7 veces lo de runc, y con Cloud Hypervisor 6,12 s, 27,3 veces. La primera hipótesis, que Kata tardaría al menos tres veces más en arrancar, se cumplió de sobra.

Esos siete segundos de QEMU son la razón de la primera enmienda: quien usa Kata en serio suele cambiar de hipervisor, así que agregué el brazo de Cloud Hypervisor. Sus corridas de arranque y compilación se hicieron después de las de los otros tres, no intercaladas; las demás cargas sí lo están.

La tabla completa

Lo que cobra cada sandbox, carga por cargaBarra: cuántas veces lo de runc, en escala logarítmica; raya: intervalo de confianza del 95 %. A la derecha, la mediana.

Arranque docker run --rm true, desde el host

runc0,224 sreferencia
gVisor0,330 s1,48×
Kata · QEMU7,09 s31,7×
Kata · CLH6,12 s27,3×

Memoria en reposo PSS de los procesos del contenedor

runc11,5 MiBreferencia
gVisor48,6 MiB4,23×
Kata · QEMU302 MiB26,4×
Kata · CLH199 MiB17,4×

Replay de comandos de agente comandos grabados filtrados, desde el host

runc0,444 sreferencia
gVisor0,835 s1,88×
Kata · QEMU7,80 s17,6×
Kata · CLH6,82 s15,4×

Compilación Lua 5.4.7, medida por dentro

runc7,21 sreferencia
gVisor8,31 s1,15×
Kata · QEMU10,0 s1,39×
Kata · CLH10,7 s1,49×

Muchos archivos pequeños venv + pip + 5.000 archivos, medida por dentro

runc15,0 sreferencia
gVisor15,4 sempate
Kata · QEMU24,2 s1,62×
Kata · CLH25,3 s1,69×

Arranque: 30 corridas por brazo; el resto, 10. Compilación y archivos medidos con un reloj dentro del contenedor, sin contar su arranque.

Carga (mediana)runcgVisorKata · QEMUKata · CLH
Arranque (docker run --rm true)0,224 s0,330 s (1,48×)7,09 s (31,7×)6,12 s (27,3×)
Memoria en reposo (PSS)11,5 MiB48,6 MiB (4,2×)302 MiB (26,4×)199 MiB (17,4×)
Replay de comandos de agente0,444 s0,835 s (1,88×)7,80 s (17,6×)6,82 s (15,4×)
Compilación, medida por dentro7,21 s8,31 s (1,15×)10,04 s (1,39×)10,70 s (1,48×)
Archivos pequeños, medida por dentro14,98 s15,44 s (empate)24,21 s (1,62×)25,34 s (1,69×)

Todas las diferencias contra runc son «más lento» o «más memoria» según la regla, salvo una: gVisor en la carga de archivos, medida por dentro, con una razón de 1,03 y un intervalo de 0,97 a 1,03.

Memoria: lo que el host ve de cada contenedor

Lo que el host ve de un contenedor en reposo en cada sandboxKERNEL DEL HOST · LINUX 6.18runc11,5 MiBgVisor48,6 MiBSentry 23 MiBKata · QEMU302 MiBVM 275 MiBKata · CLH199 MiBVM 172 MiBagenteSentry / VMPSS total
Lo que el host ve de un contenedor en reposo en cada sandbox. Columna: una franja por cada 10 MiB de PSS contada para el contenedor. Alto de cada capa: PSS del proceso que la forma.

Con runc, el host ve el proceso del contenedor y el shim de containerd: 11,5 MiB en total. gVisor suma dos procesos propios, el sandbox (su kernel en espacio de usuario, 22,5 MiB) y el gofer que sirve los archivos (13,9 MiB), y llega a 48,6 MiB. En Kata el peso es la máquina virtual: el proceso de QEMU solo ocupa 275 MiB, y el de Cloud Hypervisor 172 MiB, más el shim de Kata (24 MiB) y dos virtiofsd.

Esta cifra es la PSS observada de los procesos que mi arnés atribuyó a cada contenedor: los de su cgroup, los descendientes de su proceso inicial y los ayudantes del runtime cuya línea de comandos nombra al contenedor. Cada proceso quedó registrado con su línea de comandos completa y el motivo por el que se contó. No es la memoria total que pierde el equipo: no incluye el kernel del host ni las cachés.

El replay de comandos de agente

Esta carga es la que más me costó dejar bien, y la que hay que leer con más cuidado. Tomé los registros de comandos de seis corridas de agentes de otro experimento, los guardé byte a byte y los ejecuté en orden dentro de un contenedor nuevo, en un repositorio git con su primer commit, como en el original. El arnés filtra los comandos que tocan la configuración del propio agente, así que algunos pasos reales quedaron fuera (en una de las sesiones, las corridas de pytest). Y algunos comandos fallan igual que fallaron en la sesión original: una corrida solo cuenta si cada paso devuelve el mismo código de salida que en runc, y las 40 lo cumplen.

Por eso no lo presento como el costo de una sesión de agente funcional, sino como el de repetir un subconjunto filtrado de sus comandos. En ese replay, gVisor tardó 1,88 veces lo de runc y Kata entre 15 y 18 veces, porque el contenedor vive menos de un segundo y el arranque de la máquina virtual se come casi todo. La segunda hipótesis decía que gVisor y Kata tardarían menos de 1,5 veces lo de runc; con este replay no se cumple, pero este replay tampoco es la sesión que la hipótesis tenía en mente.

Compilación y archivos, medidos por dentro

El tiempo desde el host incluye levantar el contenedor, y en Kata eso son los 6 o 7 segundos del arranque. La segunda enmienda agregó un reloj dentro del contenedor para medir solo el trabajo. Con ese reloj, compilar Lua costó 1,15 veces lo de runc en gVisor, 1,39 en Kata con QEMU y 1,48 con Cloud Hypervisor. Desde el host, las razones de Kata suben a 2,27 y 2,15.

La carga de archivos fue la sorpresa. La tercera hipótesis decía que las operaciones con muchos archivos pequeños serían las que más encarecería gVisor, y fue al revés: medida por dentro, empató con runc. Kata, en cambio, tardó 1,6 a 1,7 veces más. En gVisor lo más caro fue el replay de comandos cortos y el arranque, no el sistema de archivos. Desde el host, la carga de archivos de gVisor quedó como no concluyente: la razón es 0,98, pero el intervalo va de 0,72 a 0,99.

Lo que se cayó en el camino

  • La línea base sin contenedor: la ficha pedía correr las cargas directamente en el host como piso. En NixOS no es comparable: el host no tiene las herramientas de las imágenes Debian, la sesión falló por rutas y la compilación usó otro GCC. La tercera enmienda la descartó y dejó a runc como referencia.
  • Tres cargas rehechas: una auditoría externa rechazó la primera versión del replay (fallaba en silencio: el repositorio no era git y algunos comandos se reescapaban mal), de la carga de archivos (podía fallar sin que el arnés lo notara) y de la memoria (la selección de procesos tenía errores). La cuarta enmienda corrigió las tres y las repetí completas, intercalando los cuatro brazos. Una segunda ronda pidió que los errores al buscar procesos no se perdieran y que cada proceso dijera por qué se contó; repetí la memoria otra vez, con las mismas cifras.
  • Kata colgado: en la primera repetición, algunos pasos del replay se quedaban esperando la entrada estándar en Kata y nunca terminaban. Ahora cada paso corre con la entrada cerrada y un tope de 120 s.

Amenazas a la validez

  • Una sola máquina, de portátil, con un SSD SATA. Los números absolutos no se trasladan a un servidor; las razones entre brazos son lo que vale.
  • Cada tecnología tiene varias configuraciones y medí la que viene por defecto (más Cloud Hypervisor). gVisor tiene otras plataformas, y Kata permite ajustar memoria y CPU de la máquina virtual o usar plantillas para arrancar más rápido; no lo probé.
  • Los mismos límites no dan los mismos recursos: dentro del contenedor, nproc dice 8 en runc, 2 en gVisor y 3 en Kata.
  • Las corridas de arranque y compilación de Cloud Hypervisor no están intercaladas con las otras.
  • El replay es un subconjunto filtrado de comandos sin llamadas al modelo; seis sesiones repartidas en diez repeticiones.
  • La memoria es la PSS de los procesos seleccionados, no la memoria total del host.
  • No guardé el estado de la caché de disco ni el digest de las imágenes en cada fila.
  • No medí seguridad ni intenté escapar de ningún sandbox.

Veredicto

Si un agente lanza un contenedor por cada comando, Kata no sirve tal cual: 6 o 7 segundos de arranque por contenedor y 200 a 300 MiB cada uno. Si el agente vive horas en el mismo contenedor, el arranque se paga una vez y lo que queda es que el trabajo dentro cuesta entre 1,4 y 1,7 veces lo de Docker, a cambio de su propio kernel. gVisor es el punto medio barato: un tercio de segundo para arrancar, unos 50 MiB, un 15 % más en compilación y nada medible con muchos archivos pequeños. Docker normal sigue siendo lo más rápido, y también lo único de los tres que comparte el kernel del host con el agente.

Preguntas frecuentes

¿Cuánto más lento arranca un contenedor en Kata que en Docker normal?

En mi máquina, un docker run --rm que solo ejecuta true tardó 0,22 s con runc, 7,09 s con Kata 4.3 y QEMU (31,7 veces más) y 6,12 s con Kata y Cloud Hypervisor (27,3 veces más). gVisor tardó 0,33 s, 1,48 veces lo de runc. Son medianas de 30 corridas por brazo.

¿Cuánta memoria usa gVisor o Kata por contenedor?

Con un contenedor en reposo, la suma de PSS de los procesos que encontré para él fue 11,5 MiB con runc, 48,6 MiB con gVisor, 302 MiB con Kata y QEMU y 199 MiB con Kata y Cloud Hypervisor. En Kata casi todo es el proceso del hipervisor: 275 MiB QEMU y 172 MiB Cloud Hypervisor. Es la memoria observada de esos procesos, no la memoria total que pierde el equipo.

¿gVisor es lento con muchos archivos pequeños?

En mi carga, no. Crear un entorno virtual de Python, instalar JupyterLab desde un índice local y descomprimir 5.000 archivos tardó 14,98 s con runc y 15,44 s con gVisor, medido por dentro del contenedor: empate según la regla que fijé antes de medir. Kata tardó 24,2 s con QEMU y 25,3 s con Cloud Hypervisor.

¿Cloud Hypervisor es mejor que QEMU para Kata?

Arranca más rápido (6,12 contra 7,09 s) y usa menos memoria (199 contra 302 MiB), pero dentro del contenedor fue un poco más lento: compilar Lua tomó 10,70 s contra 10,04 s, y la carga de archivos 25,3 contra 24,2 s. Las corridas de arranque y compilación de Cloud Hypervisor se hicieron después de las otras, no intercaladas.

¿Esto mide si un agente puede escapar del sandbox?

No. Solo mide el costo del aislamiento: tiempo y memoria. No intenté ningún escape ni evalué la seguridad de cada tecnología.

¿Puedo reproducirlo?

Sí. La ficha con las hipótesis y la regla de decisión escritas antes de medir, sus cuatro enmiendas, el arnés, el análisis y los datos crudos están en el repositorio y en un gist enlazado en las fuentes.

Fuentes

Medido el 21 y el 22 de octubre de 2026 en un portátil Lenovo con Intel Core i5-8250U, 11 GiB de RAM y SSD SATA, con NixOS y Linux 6.18. Docker 29.8.1, containerd 2.3.3, runc 1.5.1, gVisor 20260406.0, Kata Containers 4.3.0 (runtime-rs), QEMU 11.0.1, Cloud Hypervisor v54.0. Arranque: 30 corridas por brazo; resto: 10.

BOLETÍN · MEDIDO

Una medición nueva, cuando la hay.

Cada post con sus números, sus fallos y los scripts para repetirlo. Entre uno y tres correos al mes. Te das de baja con un clic.

LO ÚLTIMO QUE LLEGÓ

Uso Listmonk en mi propio servidor; tu correo no sale de ahí. Confirmas por correo antes de recibir nada.

Comentarios

Todavía no hay comentarios. El primero es tuyo.

Se revisa antes de publicarse. El correo no se guarda ni aparece en ninguna parte.