13°
Portada del artículo: Isolating a coding agent with gVisor or Kata: what it costs compared with Docker, measured
ContainersSecurityAgentsBenchmarks

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.

Efrain Garay 23 October 2026

Playing summary

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.

Narrated: the host kernel as a deck with four bays, one per sandbox, each built from what the host sees of one container. Idle memory from 11.5 to 302 MiB, a start-up race at real speed (0.22 s runc, 7.09 s Kata with QEMU) and 5,000 small files where gVisor ties with runc.Watch it in the reel viewer →

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 --rm of a minimal image that runs true, 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, make and 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.
  • 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

Start-up of docker run --rm true, at real speed (median of 30 runs)
runc0.22 sgVisor0.33 sKata · QEMU7.09 sKata · CLH6.12 s

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

What each sandbox charges, workload by workloadBar: how many times runc, on a log scale; line: 95 % confidence interval. On the right, the median.

Start-up docker run --rm true, from the host

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

Idle memory PSS of the container's processes

runc11.5 MiBreference
gVisor48.6 MiB4.23×
Kata · QEMU302 MiB26.4×
Kata · CLH199 MiB17.4×

Agent command replay filtered recorded commands, from the host

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

Compile Lua 5.4.7, timed inside

runc7.21 sreference
gVisor8.31 s1.15×
Kata · QEMU10.0 s1.39×
Kata · CLH10.7 s1.49×

Many small files venv + pip + 5,000 files, timed inside

runc15.0 sreference
gVisor15.4 stie
Kata · QEMU24.2 s1.62×
Kata · CLH25.3 s1.69×

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)runcgVisorKata · QEMUKata · CLH
Start-up (docker run --rm true)0.224 s0.330 s (1.48×)7.09 s (31.7×)6.12 s (27.3×)
Idle memory (PSS)11.5 MiB48.6 MiB (4.2×)302 MiB (26.4×)199 MiB (17.4×)
Agent command replay0.444 s0.835 s (1.88×)7.80 s (17.6×)6.82 s (15.4×)
Compile, timed inside7.21 s8.31 s (1.15×)10.04 s (1.39×)10.70 s (1.48×)
Small files, timed inside14.98 s15.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

What the host sees of one idle container in each sandboxHOST KERNEL · LINUX 6.18runc11.5 MiBgVisor48.6 MiBSentry 23 MiBKata · QEMU302 MiBVM 275 MiBKata · CLH199 MiBVM 172 MiBagentSentry / VMtotal PSS
What the host sees of one idle container in each sandbox. Column: one band per 10 MiB of PSS counted for the container. Layer height: PSS of the process that makes it.

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, nproc says 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

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

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.

Reviewed before publishing. The email is not stored and never appears anywhere.