
Isolating a coding agent with gVisor or Kata: what it costs compared with Docker, measured
I measured what it costs to run a coding agent's work isolated in gVisor and in Kata Containers 4.3 (with QEMU and with Cloud Hypervisor) instead of a plain Docker container. Kata takes 6 to 7 s to start against 0.22 s for runc and leaves 199 to 302 MiB per container against 11.5; gVisor starts in 0.33 s, uses 48.6 MiB and ties with runc on a workload of thousands of small files.
I let coding agents run commands on my machines, and the fear I hear most when people talk about that is an agent breaking something outside its folder. The usual answer is to isolate it more: instead of a plain Docker container, a sandbox like gVisor, which puts a kernel written in user space in front of it, or Kata Containers, which puts each container in a lightweight virtual machine with its own kernel. I wanted to know what that costs in time and memory with agent work, on the same machine and with the same limits.
I did not test whether they can be escaped. That is another study. Here I measured only the price of the protection.
What I measured, and under which rules
Before the first run I wrote a sheet with the question, three hypotheses and the decision rule, and amended it in writing four times; each amendment says why.
- Machine: a Lenovo laptop with an Intel Core i5-8250U (4 cores, 8 threads), 11 GiB of RAM and a SATA SSD, running NixOS, Linux 6.18 and KVM.
- Arms: Docker 29.8 with its default runtime, runc 1.5.1 (the reference). gVisor (runsc 20260406.0, the nixpkgs build) with its default platform. Kata Containers 4.3.0 with the official static binaries and its default configuration, which uses QEMU 11.0. And, through an amendment I explain below, the same Kata with its official Cloud Hypervisor v54 configuration.
- Limits: every container with
--cpus 2 --memory 2g --network none. - Workloads: five, each with the same image in the four arms:
- Start-up:
docker run --rmof a minimal image that runstrue, timed from the host. 30 runs per arm. - Memory: an idle container (
sleep 300) and, after 10 seconds, the sum of the PSS of its processes on the host. 10 runs. - Agent command replay: the commands that real agents ran in another experiment of mine, not yet published, replayed in order inside a new container. 10 runs.
- Compile: the whole of Lua 5.4.7,
makeand clean. 10 runs. - Many small files: create a Python virtual environment, install JupyterLab from a local index without network and extract a tree of 5,000 files. 10 runs.
- Start-up:
- Rule: median per arm and ratio against runc, with a 95 % bootstrap confidence interval (10,000 resamples, seed 17). “Slower” if the interval excludes 1 and the ratio exceeds 1.10; “tie” only if the whole interval falls between 0.95 and 1.05.
Start-up: Kata needs seconds
runc started and finished the container in 0.22 s; gVisor in 0.33 s, 1.48 times as long. Kata with QEMU took 7.09 s, 31.7 times runc, and with Cloud Hypervisor 6.12 s, 27.3 times. The first hypothesis, that Kata would take at least three times as long to start, held by a wide margin.
Those seven seconds of QEMU are the reason for the first amendment: people who use Kata seriously tend to switch hypervisors, so I added the Cloud Hypervisor arm. Its start-up and compile runs were done after those of the other three, not interleaved; the other workloads are.
The full table
Start-up docker run --rm true, from the host
Idle memory PSS of the container's processes
Agent command replay filtered recorded commands, from the host
Compile Lua 5.4.7, timed inside
Many small files venv + pip + 5,000 files, timed inside
Start-up: 30 runs per arm; the rest, 10. Compile and files timed with a clock inside the container, without its start-up.
| Workload (median) | runc | gVisor | Kata · QEMU | Kata · CLH |
|---|---|---|---|---|
Start-up (docker run --rm true) | 0.224 s | 0.330 s (1.48×) | 7.09 s (31.7×) | 6.12 s (27.3×) |
| Idle memory (PSS) | 11.5 MiB | 48.6 MiB (4.2×) | 302 MiB (26.4×) | 199 MiB (17.4×) |
| Agent command replay | 0.444 s | 0.835 s (1.88×) | 7.80 s (17.6×) | 6.82 s (15.4×) |
| Compile, timed inside | 7.21 s | 8.31 s (1.15×) | 10.04 s (1.39×) | 10.70 s (1.48×) |
| Small files, timed inside | 14.98 s | 15.44 s (tie) | 24.21 s (1.62×) | 25.34 s (1.69×) |
Every difference against runc is “slower” or “more memory” under the rule, except one: gVisor on the files workload, timed inside, with a ratio of 1.03 and an interval from 0.97 to 1.03.
Memory: what the host sees of each container
With runc, the host sees the container’s process and containerd’s shim: 11.5 MiB in total. gVisor adds two processes of its own, the sandbox (its user-space kernel, 22.5 MiB) and the gofer that serves files (13.9 MiB), and reaches 48.6 MiB. In Kata the weight is the virtual machine: the QEMU process alone takes 275 MiB, and Cloud Hypervisor’s 172 MiB, plus Kata’s shim (24 MiB) and two virtiofsd.
This figure is the observed PSS of the processes my harness attributed to each container: those in its cgroup, the descendants of its init process and the runtime helpers whose command line names the container. Each process was recorded with its full command line and the reason it was counted. It is not the total memory the machine loses: it does not include the host kernel or the caches.
The agent command replay
This is the workload that was hardest to get right, and the one to read most carefully. I took the command logs of six agent runs from another experiment, stored them byte for byte and ran them in order inside a new container, in a git repository with its first commit, as in the original. The harness filters out the commands that touch the agent’s own configuration, so some real steps were left out (in one of the sessions, the pytest runs). And some commands fail just as they failed in the original session: a run only counts if every step returns the same exit code as in runc, and all 40 do.
So I do not present it as the cost of a working agent session, but as the cost of replaying a filtered subset of its commands. In that replay, gVisor took 1.88 times runc and Kata 15 to 18 times, because the container lives for less than a second and the virtual machine’s start-up eats almost all of it. The second hypothesis said gVisor and Kata would take less than 1.5 times runc; with this replay it does not hold, but this replay is not the session the hypothesis had in mind either.
Compile and files, timed inside
The time from the host includes bringing the container up, and in Kata that is the 6 or 7 seconds of start-up. The second amendment added a clock inside the container to time only the work. With that clock, compiling Lua cost 1.15 times runc in gVisor, 1.39 in Kata with QEMU and 1.48 with Cloud Hypervisor. From the host, Kata’s ratios rise to 2.27 and 2.15.
The files workload was the surprise. The third hypothesis said that operations with many small files would be the ones gVisor made most expensive, and it went the other way: timed inside, it tied with runc. Kata, on the other hand, took 1.6 to 1.7 times as long. In gVisor the most expensive things were the replay of short commands and the start-up, not the file system. From the host, gVisor’s files workload came out inconclusive: the ratio is 0.98, but the interval runs from 0.72 to 0.99.
What fell along the way
- The no-container baseline: the sheet asked to run the workloads directly on the host as a floor. On NixOS it is not comparable: the host lacks the tools of the Debian images, the session failed on paths and the compile used another GCC. The third amendment dropped it and left runc as the reference.
- Three workloads redone: an external audit rejected the first version of the replay (it failed silently: the repository was not a git one and some commands were re-escaped wrongly), of the files workload (it could fail without the harness noticing) and of the memory one (the process selection had errors). The fourth amendment fixed the three and I reran them in full, interleaving the four arms. A second round asked for errors while finding processes not to be lost and for each process to say why it was counted; I reran memory again, with the same figures.
- Kata hanging: in the first rerun, some replay steps sat waiting for standard input in Kata and never finished. Now each step runs with input closed and a 120 s cap.
Threats to validity
- One machine, a laptop, with a SATA SSD. The absolute numbers do not carry over to a server; the ratios between arms are what counts.
- Each technology has several configurations and I measured the default one (plus Cloud Hypervisor). gVisor has other platforms, and Kata lets you tune the virtual machine’s memory and CPU or use templates to start faster; I did not try them.
- The same limits do not give the same resources: inside the container,
nprocsays 8 in runc, 2 in gVisor and 3 in Kata. - Cloud Hypervisor’s start-up and compile runs are not interleaved with the others.
- The replay is a filtered subset of commands without model calls; six sessions spread over ten repetitions.
- Memory is the PSS of the selected processes, not the host’s total memory.
- I did not record the disk cache state or the image digest in each row.
- I did not measure security or try to escape any sandbox.
Verdict
If an agent launches a container for each command, Kata does not work as is: 6 or 7 seconds of start-up per container and 200 to 300 MiB each. If the agent lives for hours in the same container, the start-up is paid once and what remains is that the work inside costs 1.4 to 1.7 times Docker, in exchange for its own kernel. gVisor is the cheap middle ground: a third of a second to start, about 50 MiB, 15 % more on compiling and nothing measurable with many small files. Plain Docker is still the fastest, and also the only one of the three that shares the host kernel with the agent.
Frequently asked questions
How much slower does a container start in Kata than in plain Docker?
On my machine, a docker run --rm that only runs true took 0.22 s with runc, 7.09 s with Kata 4.3 and QEMU (31.7 times as long) and 6.12 s with Kata and Cloud Hypervisor (27.3 times). gVisor took 0.33 s, 1.48 times runc. Medians of 30 runs per arm.
How much memory does gVisor or Kata use per container?
With an idle container, the PSS of the processes I found for it added up to 11.5 MiB with runc, 48.6 MiB with gVisor, 302 MiB with Kata and QEMU and 199 MiB with Kata and Cloud Hypervisor. In Kata almost all of it is the hypervisor process: 275 MiB for QEMU and 172 MiB for Cloud Hypervisor. It is the observed memory of those processes, not the total memory the machine loses.
Is gVisor slow with many small files?
On my workload, no. Creating a Python virtual environment, installing JupyterLab from a local index and extracting 5,000 files took 14.98 s with runc and 15.44 s with gVisor, timed inside the container: a tie under the rule I fixed before measuring. Kata took 24.2 s with QEMU and 25.3 s with Cloud Hypervisor.
Is Cloud Hypervisor better than QEMU for Kata?
It starts faster (6.12 against 7.09 s) and uses less memory (199 against 302 MiB), but inside the container it was slightly slower: compiling Lua took 10.70 s against 10.04 s, and the files workload 25.3 against 24.2 s. Cloud Hypervisor's start-up and compile runs were done after the others, not interleaved.
Does this measure whether an agent can escape the sandbox?
No. It only measures the cost of the isolation: time and memory. I did not attempt any escape or evaluate the security of each technology.
Can I reproduce it?
Yes. The sheet with the hypotheses and the decision rule written before measuring, its four amendments, the harness, the analysis and the raw data are in the repository and in a gist linked in the sources.
Sources
- gVisor: architecture guide and its repository.
- Kata Containers and its 4.3.0 release.
- Cloud Hypervisor and QEMU.
- Docker: alternative runtimes.
- The Linux kernel: PSS in /proc/<pid>/smaps_rollup.
- Lua 5.4.7 and JupyterLab.
- The sheet, the harness, the analysis and the raw data.
Measured on 21 and 22 October 2026 on a Lenovo laptop with an Intel Core i5-8250U, 11 GiB of RAM and a SATA SSD, running NixOS and 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. Start-up: 30 runs per arm; the rest: 10.
NEWSLETTER · MEASURED
A new measurement, when there is one.
Each post with its numbers, its failures and the scripts to repeat it. One to three emails a month. Unsubscribe with one click.
LATEST
- 7 harnesses on MiniMax-M329 of 39 with the simplest harness
- runc vs gVisor vs KataKata starts 27× slower
- ComfyUI vs Forge on 16 GB2× with Z-Image
I run Listmonk on my own server; your address stays there. You confirm by email before getting anything.
Comments
No comments yet. The first one is yours.