Pular para o conteúdo
← Back to Skalablog

Published article

Docker, gVisor, or Firecracker for AI Agents

Software EngineeringOpenAI

Docker, gVisor, or Firecracker for AI agents comes down to one question: who answers the system call the agent's code makes? In a standard Docker container the host kernel answers it, gVisor's Sentry answers it in user space, and a Firecracker microVM hands it to a guest kernel behind KVM.

Who answers the system call in each sandbox?

Docker, gVisor, or Firecracker for AI agents reduces to one question: which kernel answers the system call the agent's code makes. In a Docker container the host kernel answers directly, gVisor's Sentry answers in user space, and a Firecracker microVM routes the call into a guest kernel running under KVM. Docker's container documentation describes namespaces as giving a container its own view of processes and network, and cgroups as limiting what it can use. Neither feature separates the process from the host kernel, so the call crosses straight into it.

A program cannot OpenAI file, use the network, or allocate memory on its own. It asks the kernel through a system call, which is why the identity of the answering kernel sets the width of the attack surface. In gVisor the answering code is the Sentry, an application kernel written in Go that runs outside the host kernel. In a microVM the answering code is a separate Linux kernel inside the guest, and the host side only sees KVM plus a small device model.

The transcript frames this as three houses: a Docker container keeps the visitor in the same house behind a door, gVisor puts a receptionist in front so the visitor never enters, and a microVM moves the visitor to a separate building. The metaphor holds because the mechanism it describes is the same in each case — the code's request has to be handled by something other than the code itself.

How containers, gVisor and microVMs differ

The three boxes differ in how much software stands between agent-written code and the host. A container adds almost none on the call path; gVisor adds a Sentry plus a gofer process for file I/O; a microVM adds hardware virtualization, a guest kernel, and a per-VM boot and memory cost.

SandboxWho answers the callHost exposureExtra cost per call
Docker containerHost kernelFull kernel surface, plus runcNone
gVisorSentry (user space, Go)Limited set of host callsSentry layer, gofer for file I/O
Firecracker microVMGuest kernel under KVMKVM plus small device modelVM boot, monitor memory

Namespaces and cgroups are kernel features, so every container on a machine shares the same host kernel. That is the structural difference from the other two options: containers change what a process can see and how much it can consume, while gVisor and microVMs change which kernel handles the request.

The practical consequence is that a bug anywhere in the shared path — the kernel or the tool that starts the container — can carry code out of the container. The same bug class exists in a hypervisor or in gVisor. No box is unescapable, so the useful comparison is the size of the boundary, not the promise of perfect isolation.

Which runc escape bugs matter

runc, the low-level tool that starts containers for Docker, containerd, and Kubernetes, has disclosed several escape bugs that matter for anyone running agent-written code. The CVE-2024-21626 advisory — Leaky Vessels — was published on January 31, 2024, caused by an internal file descriptor leak that let a process started by runc exec or a malicious image carry a working directory inside the host filesystem. It is rated 8.6, high, on the CVSS scale.

The advisory states that all four attacks it covers can give full control of the host. An earlier bug with the same 8.6 score, CVE-2019-5736, let a malicious container overwrite the host's runc binary through a mishandled file descriptor, and it required the attacker to have root inside the container. A correct user namespace setup where host root is not mapped blocked that attack; the default AppArmor policy and Fedora's SELinux policy did not.

The class is not historical. A November 2025 runc advisory covers CVE-2025-31133, a timing bug in how runc hides sensitive host paths from a container, rated 7.3, high. Patch releases fix each of these, so the actionable step is to track the runc version your container runtime ships rather than to treat any single CVE as the last one.

Update runc before anything else. Every bug above has a fixed release, and a container running an unpatched runc offers the weakest boundary of the three options regardless of how carefully the workload is written.

How Google gVisor's Sentry and Systrap shrink host exposure

gVisor's core is the Sentry, an application kernel written in Go that catches the code's system calls and memory access requests and answers them with its own implementations of system calls, memory, file systems, networking, and processes. Google's gVisor documentation states that the Sentry never passes a system call from the containerized code through to the host, though the Sentry itself makes a limited set of host calls for its own work.

Those numbers come from gVisor's own 2019 post measured against Linux 5.3.11, so the current list may differ. In that count, Linux had about 350 system calls, the Sentry implemented 237 of them for containers, and it may use only 68 distinct host system calls — 53 without networking and 15 more with it. The Sentry cannot open or create host files at all; all file I/O goes through gofer helper processes, so a file request travels from the code to the Sentry and then to a gofer that touches the host file.

The Sentry is software, so it can have bugs, and a Sentry flaw could let code reach further than the design intends. gVisor reduces host exposure rather than eliminating it, which is why the honest reading of the 68-call figure is a smaller opening, not a closed one.

What the platform setting changes

The platform setting chooses how gVisor catches calls. Since mid-2023 the default has been systrap, built on seccomp, where a return-trap rule makes the host kernel deliver a signal to the calling thread and hand control to gVisor. The older ptrace platform is described as obsolete in gVisor's documentation.

gVisor's 2023 post reported systrap running about 10 times faster than ptrace on a loop of getpid calls, about two times faster on a compile, and two to three times faster on Redis, with FFmpeg barely changing. That comparison is gVisor against itself, not gVisor against Docker, and the numbers should not be transferred to a different workload.

What gVisor costs your agent's workload

gVisor's performance guide splits the cost into two parts: the structural cost of the extra Sentry layer and the gofer path for files, and the implementation cost of gVisor's own file system and network stack, which are less mature than Linux's. Apps bound by system calls pay the most, and compute-bound code plus raw memory access carry no extra cost once memory mappings are in place.

The guidance that follows is specific: data stores and static network services feel the penalty hardest, and memory overhead is a small, mostly fixed amount. An agent that spends its time in a database or a network server should be benchmarked on that exact work in gVisor before it ships, because the cost tracks system call volume rather than CPU time.

For an agent whose work is mostly computation, gVisor avoids the per-VM boot that a microVM requires. For an agent that opens many files or serves many connections, the gofer path is the part of the design that determines the bill.

How Firecracker microVMs put a guest kernel around the code

Firecracker is the microVM monitor AWS built for Lambda and Fargate and later released as an open-source project under Apache 2.0. It uses KVM, the Linux feature that lets the CPU run a guest kernel, so the code's system call lands in that guest kernel and the host sees only KVM plus a small device model.

That device model is deliberately small. Firecracker exposes virtio network and block devices, a vsock channel between guest and host, a serial console, and a partial keyboard controller that only signals a reboot. Each Firecracker process runs three kinds of thread: an API thread, one VMM thread emulating devices in a single event loop, and one VCPU thread per guest core. A jailer applies cgroup and namespace isolation to the process then drops privileges, and Firecracker loads seccomp filters for each thread before any guest code runs — so Firecracker itself operates under Linux limits too.

The published design targets come from AWS bare-metal hosts with a guest that has one VCPU and 128 MiB of memory. On those hosts, guest init starts 125 ms or less after the API call that starts the instance, and the VMM thread adds 5 MiB or less of memory overhead. The 125 ms ends when init starts, not when the agent's code runs, and the spec states no number for a full agent image.

Firecracker also states about 0.06 ms of added network latency from virtualization and guest CPU speed above 95% of bare metal, with the spec marking that CPU test as pending. Those are vendor-published design targets, not independent measurements.

Does Docker Desktop on macOS already use microVMs?

On macOS, Docker Desktop runs containers inside a Linux virtual machine, so the isolation boundary changes and a runc escape lands in that Linux VM before it reaches macOS. Docker's documentation lists three backends: Docker VMM, described as a container-optimized virtual machine manager, the Apple virtualization framework, and the legacy hyperkit, which Docker marks as deprecated and Intel-only.

On October 3, 2026, Dave Scott argued in a Docker blog post that Docker Desktop has used microVMs since 2016, defining a microVM as a workload on a stripped-down Linux kernel running on a minimal VMM. Docker's own documentation says Linux VM rather than microVM, and the docs do not state how Docker VMM compares with Firecracker or what shared folders do to the boundary. Treat the microVM label as his framing.

Docker ships a first-party agent product with the same design. Docker Sandboxes, described in an April 16, 2026 post, runs each agent session in a dedicated microVM with its own kernel and a private Docker daemon, using hypervisor.framework on macOS, the Windows Hyper-V Platform on Windows, and KVM on Linux. Docker's stated reason goes beyond escape risk: an agent that builds containers needs Docker in Docker, which requires privileges that weaken container isolation. The post gives no startup or memory numbers.

Which sandbox should you pick for an agent?

Pick a patched Docker container for code you wrote and reviewed, gVisor when the workload is mostly compute and you cannot pay a VM boot, and a microVM when the code is hostile or the agent builds containers. That ranking follows the mechanism rather than a head-to-head test: no source in this material compares escape bugs across the three boxes on one machine.

  1. For code you wrote and reviewed, a normal Docker container sends calls straight to the host kernel with no extra layer on the call path. Keep runc updated, since each escape bug above has a fixed release.

2. For code that comes from web pages or files you do not control, assume a prompt injection can steer it and treat the code as hostile. A shared kernel is the wrong place for that.

3. For compute-heavy work where a VM boot is too expensive, gVisor removes the boot cost and accepts a system call penalty. Test it on the real workload first if the agent runs a database or a network server.

4. For agents that build containers or run code from people you do not know, a microVM gives the code its own kernel behind hardware virtualization. The cost is 5 MiB or less of monitor memory plus the memory you give the guest, plus a VM boot. Docker chose the same shape for its own agent product.

Governance of gVisor changed on October 2, 2026, when Google announced it was donating the project to the CNCF, which accepted it on September 28. gVisor starts at the CNCF's first maturity level, named sandbox, with a plan to move to incubation, and governance shifts to maintainers with organization-based voting so Google cannot decide alone. The announcement carries no technical detail and no performance numbers, so it changes who governs gVisor rather than how fast or how secure it is.

FAQ

  • Is a Docker container enough to isolate AI agent code? It is enough when you wrote and reviewed the code, because container isolation relies on the shared host kernel. Namespaces and cgroups limit what a process sees and uses without separating it from that kernel, and runc escape bugs have broken the boundary repeatedly.
  • What is the main difference between gVisor and a Firecracker microVM? gVisor answers system calls in a user-space kernel called the Sentry, so it adds a software layer without a VM boot. Firecracker runs a real guest kernel under KVM with a minimal device model, which costs a boot and monitor memory in exchange for hardware-level separation.
  • How much memory does a Firecracker microVM add? Firecracker's published design targets state 5 MiB or less of monitor memory overhead per VM on AWS bare-metal hosts with a one-VCPU, 128 MiB guest. That figure excludes the memory you assign to the guest itself.
  • Why does gVisor slow some workloads down? gVisor's performance guide separates structural cost, the Sentry layer and the gofer path for files, from implementation cost, its own file system and network stack. Data stores and static network services feel the penalty hardest because they issue many system calls.
  • Do runc vulnerabilities still get disclosed? Yes. CVE-2019-5736 and CVE-2024-21626 both scored 8.6, high, and a November 2025 advisory covers CVE-2025-31133, a timing bug rated 7.3, high. Each has a fixed release, so version tracking matters more than any single patch.
  • What does the CNCF donation change about gVisor? It moves governance to maintainers with organization-based voting and starts gVisor at the CNCF's sandbox maturity level with a plan for incubation. Google's October 2026 announcement includes no technical or performance detail.
  • Can a microVM stop a prompt injection? No. Isolation limits how far injected code can reach after it runs; it does not stop the agent from being steered. Treat code sourced from pages or files you do not control as hostile and give it the smallest boundary you can afford.
  • Does Docker Desktop on macOS give containers a separate kernel? Yes. Docker Desktop runs containers inside a Linux virtual machine on macOS, so a container escape lands in that VM before it reaches the host. Docker's documentation names three backends: Docker VMM, the Apple virtualization framework, and the deprecated hyperkit.
  • Which sandbox should run an agent that builds containers? A microVM, because nested Docker requires privileges that weaken container isolation. Docker's own Sandboxes product takes this route, running each agent session in a dedicated microVM with a private Docker daemon and its own kernel.
  • Can you benchmark all three sandboxes on one machine? Not from the sources covered here. The published figures come from different setups and dates, so any side-by-side number should come from your own workload measured in each box.

The boundary is the product decision

The choice between Docker, gVisor, and Firecracker is a choice about how much software stands between agent-written code and the machine that holds your files. A container offers the shortest path to the host kernel. gVisor inserts a Go program that implements the calls itself. A microVM inserts hardware virtualization and a second kernel.

Each option costs something measurable, and the costs are not interchangeable. gVisor trades system call throughput for the absence of a VM boot. Firecracker trades a boot and a few mebibytes of monitor memory for a kernel the agent's code cannot cross with a single bug. The runc advisories are the evidence that the container boundary is real but thin.

None of the three removes the need to patch, and none of them stops a prompt injection from steering an agent. What they change is how far the damage can travel once the code is already running. That is the question worth answering before the agent gets a terminal.

Turn the walkthrough into an article with Skala Blog

Following one system call through three isolation boundaries is the kind of explanation that only lands when someone walks it step by step, which is exactly why the original video works better than a spec sheet. The same material also deserves to be readable, linkable, and searchable for the developer deciding which box to give their agent.

If you have that kind of knowledge recorded in a YouTube video — a walkthrough, a comparison, a debugging session, or an opinion backed by evidence — Skala Blog turns it into a written article you can edit and publish. You paste the video URL, the transcript is generated, and a draft article comes back with structure and sources in place.

Skala Blog is built for people with real experience in tools like Crazystack TypeScript, and the same flow works for anything from Dev Doido's channel to a niche infrastructure deep dive. The community around Crazystack writes the kind of technical material that benefits from a written version, and a transcript is usually the only thing standing between a good video and a good article.

Source video