No per-service fees - one plan, unlimited appsFree tier available - start building today15% off your workspace - subscribe to our blogNo per-service fees - one plan, unlimited appsFree tier available - start building today15% off your workspace - subscribe to our blog
Miget x AIPlansEnterpriseCompareBlogDashboard
Start for Free
Blog/Miget/Containers/
·

gVisor vs Kata Containers: Two Ways to Stop Sharing a Kernel

A container is not the security boundary most people assume it is. When you docker run, your process talks to the same Linux kernel as every other container on that machine. Namespaces and cgroups decide what it can see and how much it can use, but the syscall interface underneath is shared, and it is enormous. A bug in any of it is potentially a way out.

For most people that is fine: if every container on the host is yours, an escape moves an attacker from your code to your other code. The calculus changes completely when the containers belong to different people - a hosting platform, a CI runner, a notebook service, an AI agent executing code it just wrote. Then the shared kernel is the only thing between two strangers.

gVisor and Kata Containers are the two mature answers, and they are philosophically opposed. This post covers how each actually works, what each project itself documents as its limits, and which workloads belong on which. Every technical claim below comes from the projects' own documentation. Disclosure: Miget runs every workload in its own MicroVM under Cloud Hypervisor, which puts us in one of these two camps - so the section on what our camp costs is the one to read closely.

gVisor: reimplement the kernel in user space

gVisor stops the container from talking to the host kernel at all. A process called the Sentry implements the Linux syscall interface itself, in Go, in user space. gVisor's own docs describe it as "either a merged guest kernel and VMM, or as seccomp on steroids," and the Sentry's scope is deliberately broad: "system calls, signal delivery, memory management and page faulting logic, the threading model, and more."

The key property is that nothing passes through. From the security model: "No system call is passed through directly to the host. Every supported call has an independent implementation in the Sentry." File access goes to a separate Gofer process over the 9P protocol, and the Sentry itself runs "in a restricted seccomp container without access to file system resources." The entry point is runsc, an OCI-compatible runtime, so it drops into existing tooling.

How syscalls get intercepted is called a platform, and there are exactly three. Systrap replaced ptrace as the default in mid-2023, using seccomp's SECCOMP_RET_TRAP to send SIGSYS to the calling thread and hand control to gVisor. Ptrace still exists in the codebase, but the docs are blunt: "it is no longer supported and is expected to eventually be removed entirely." A KVM platform also exists, and the project's guidance is worth knowing: KVM performs best on bare metal, systrap is the better choice inside a VM or on a machine without virtualization support.

gVisor states its own trade-off plainly - the flexible, thread-based resource footprint "comes at the price of reduced application compatibility and higher per-system call overhead." The compatibility gaps it documents are specific, and they are the most useful part of this whole comparison:

  • cgroups inside the sandbox exist for accounting, but "resource limits are not enforced within the sandbox."
  • "Block device filesystems like fat32, ext3, ext4 are not natively supported inside the gVisor kernel."
  • "iptables are only partially supported."
  • "io_uring is disabled by default. When enabled, its implementation is limited to basic I/O operations." The same applies to nftables.
  • Device files are generally unsupported, with NVIDIA GPUs and TPUs as the exceptions.
  • "Usage of KVM from within the sandbox is not supported" - so no nested virtualization.

On performance, gVisor is precise about where the cost is and is not: CPU work is untouched ("no runtime cost imposed for CPU operations"), memory access after mapping is untouched, and the cost concentrates in syscalls, which "will principally impact applications that are system call bound, which tend to be high-performance data stores and static network services." One caveat almost nobody repeats: gVisor's published benchmark charts were produced on the ptrace platform, which the same documentation calls unrepresentative and slated for removal. Any overhead figure that traces back to those charts describes a configuration that is no longer the default.

Networking runs through netstack, gVisor's own user-space network stack, with --network=host available as an opt-out that "trades the security and isolation of netstack for the performance of native Linux networking."

Who runs it: Google says gVisor "powers Google Cloud offerings GKE Sandbox, Cloud Run, App Engine" with "millions of gVisor sandbox instances running daily." One nuance the shorthand misses - Cloud Run's docs specify that gVisor applies to the first generation execution environment, while the second generation offers "full Linux compatibility." Beyond Google, gVisor's published user list includes Anthropic (containing code execution in claude.ai), OpenAI, Cloudflare (Pages builds), DigitalOcean App Platform, Modal, and Ant Group.

Kata Containers: give every workload a real kernel

Kata's answer is the older idea with modern tooling: if the problem is a shared kernel, stop sharing one. Each pod or sandbox runs in a lightweight VM with its own guest kernel on hardware virtualization, with a Rust agent (kata-agent) inside supervising the workload and virtiofsd sharing the OCI bundle in.

It hides behind standard interfaces. Kata implements the containerd shim v2 API (containerd-shim-kata-v2), so Kubernetes schedules it through a RuntimeClass like any other runtime, and one shim serves a whole pod rather than "2N+1 shims."

Kata 4.0.0, released 20 July 2026, is a bigger change than the version number suggests. The runtime has been rewritten from Go to Rust, and this new runtime-rs is now the default. The release notes are candid that "if you are already a Kata user you might notice some minor differences in configuration and behavior when you switch over." The default VMM mode changed too: Dragonball, a VMM linked directly into the shim process, is now "the default and recommended configuration for users, as it offers superior performance and resource efficiency," while running QEMU, Cloud Hypervisor or Firecracker as separate processes "introduces overhead due to context switching and cross-process communication." The security argument is unchanged - "The security boundary remains established by the hypervisor (hardware virtualization)."

Which hypervisor you pick matters more than most comparisons admit, and Kata's own table is explicit about the consequences:

HypervisorLanguageGPUIntel TDX / AMD SEV-SNP
QEMUCYesYes
Cloud HypervisorRustNoNo
FirecrackerRustNoNo
DragonballRustNoNo
StratoVirtRustNoNo

In Kata's words, "QEMU is the best supported hypervisor for NVIDIA-based GPUs and for confidential computing use-cases." So "we run Kata" is an incomplete sentence: a Kata deployment on QEMU and one on Dragonball have materially different capabilities. We compare the two most common standalone MicroVM monitors in Cloud Hypervisor vs Firecracker.

The costs of the VM approach:

  • A memory floor per workload. Every sandbox carries a guest kernel plus a VMM. Notably, Kata publishes no official per-sandbox memory or boot-time figures - the docs offer qualitative ratings ("Resource Overhead: Lowest") rather than numbers. If you have seen a specific millisecond figure for Kata boot time in a blog post, it did not come from Kata.
  • A VM boot that runc did not have. Negligible for a long-lived service, potentially decisive for a function invoked thousands of times a second.
  • Real plumbing. Storage crosses as virtio-fs or block devices, networking is a virtual NIC, devices need explicit passthrough. All solvable, all more moving parts than a bind mount.
  • It needs virtualization. Bare metal or nested virt. Northflank, which runs both technologies, publishes exactly this as its reason for also running gVisor: GPU workloads where nested virtualization is unavailable.

Kata is Apache 2.0, governed by an elected Architecture Committee under the Open Infrastructure Foundation.

The comparison, honestly

gVisorKata Containers
BoundarySoftware: syscalls served by a user-space kernelHardware: KVM, separate guest kernel
KernelReimplemented (Sentry, Go)A real Linux kernel per sandbox
CompatibilityBroad, with documented gaps (io_uring, iptables, ext4, nested KVM)Effectively total - it is Linux
Memory overheadLower; thread and mapping basedGuest kernel + VMM per sandbox
Syscall-heavy workPays interception costNative guest-kernel speed
GPUNVIDIA and TPU supportedOnly on the QEMU path
Confidential computingNot applicableTDX / SEV-SNP on QEMU
Host requirementStandard LinuxVirtualization available
Nested virtualization insideNot supportedPossible
Published overhead numbersCharts, from a deprecated platformNone

The framing that survives contact with reality: gVisor optimizes for density and deployability, Kata optimizes for compatibility and boundary strength. Neither is categorically "more secure." gVisor's attack surface is the Sentry's own code plus the restricted set of host syscalls it may make; Kata's is the hypervisor, the virtio device implementations, and the CPU's virtualization features. Both have had vulnerabilities. Both are run by organizations that take this extremely seriously - and, tellingly, several run both, choosing per workload.

What comparison posts usually leave out

Three things that decide real deployments and rarely appear in a feature table:

The hypervisor choice matters more than the runtime choice. As the table above shows, whether a Kata deployment can attach a GPU or run a confidential VM depends on the VMM underneath, not on Kata. A "Kata vs gVisor" decision made without naming the hypervisor is half a decision.

Version drift is a real hazard here. Kata just changed its default runtime and its default VMM in 4.0. Firecracker added PCI support in v1.13.0 and device hotplug in v1.16.0, which makes the widely-repeated description of its "minimal, MMIO-only device model" stale - including, at the time of writing, entries in Kata's own comparison docs and Firecracker's own FAQ. If a post about these projects does not state versions, treat its capability claims as undated.

Almost every performance number in circulation is unsourced. Kata publishes none. gVisor's come from a deprecated platform. Firecracker is the exception, and the contrast is instructive: its specification states <= 125 ms from the InstanceStart API call to the guest's /sbin/init, and <= 5 MiB of VMM memory overhead for a 1 vCPU / 128 MiB microVM - then adds that "these specifications are enforced by integration tests." That is what a defensible number looks like. Treat everything else as a hypothesis to measure on your own hardware.

How to choose

  1. Do you control the code you run? If yes, plain runc with good practice is defensible and the rest is architecture tourism. If no, pick one of these two.
  2. How weird are your workloads? If tenants might use io_uring, need full iptables, mount block filesystems, or run nested VMs, gVisor's documented gaps are disqualifying and Kata is the answer. If they are ordinary application processes, gVisor's surface is very likely sufficient, and its production user list is evidence at scale.
  3. What is your density target? Thousands of small, short-lived sandboxes per host favor gVisor's lower floor. Fewer, longer-lived, larger workloads make a per-sandbox VM a rounding error.
  4. Do you need GPUs or confidential computing? gVisor supports NVIDIA GPUs and TPUs; Kata needs the QEMU path for GPUs or for TDX and SEV-SNP. This question eliminates options faster than any other.

Question three decided it for us. Miget runs long-lived application workloads and managed databases, not millions of ephemeral invocations, so a per-workload VM floor is affordable, and in exchange every customer workload gets its own kernel and a hardware boundary. The Fair Scheduler then handles what a VM boundary does not: keeping a busy neighbor from taking CPU that belongs to you. If our workload mix looked like Cloud Run's, the arithmetic would point the other way and this would be a different post.

Frequently asked questions

Is gVisor or Kata Containers more secure?

Neither, categorically. They have different attack surfaces: gVisor's is the Sentry plus its restricted host syscall set; Kata's is the hypervisor and its virtio devices, enforced by the CPU. Both are far stronger than a shared host kernel, which is the comparison that actually matters. Choose on compatibility, hardware needs, and density instead.

What does gVisor not support?

The project documents the gaps: resource limits are not enforced by in-sandbox cgroups, block device filesystems like ext4 and fat32 are not natively supported, iptables are partially supported, io_uring is disabled by default and limited when enabled, device files are unsupported except NVIDIA GPUs and TPUs, and KVM cannot be used from inside the sandbox. gVisor's own advice is pragmatic: "The only real way to know if it will work is to try."

Can I use either one with Kubernetes?

Yes, both through RuntimeClass, with no other manifest changes. gVisor is available as a managed option in GKE Sandbox; Kata installs via kata-deploy, which registers the runtime class for you.

Does Kata make containers start slower?

Compared to runc, yes, because there is a VM boot where there was none. How much slower depends on the version and the hypervisor, and Kata publishes no official figure - measure it on your own hardware rather than trusting a number from a blog post.

What does Miget use?

Every workload runs in its own MicroVM under Cloud Hypervisor, which puts us in the hardware-boundary camp. That follows from our workload mix - long-lived apps and databases rather than ephemeral functions - and it is why apps, workers, databases and preview environments can share one flat-rate plan without sharing a kernel.

Do I need to care about this as an application developer?

Usually not, and that is the point: on a platform that has made the choice for you, your Dockerfile does not change. It matters when you operate the platform, or when you are deciding whose platform to trust with code that runs next to strangers. The useful question for a vendor is simply: what is the boundary between my workload and the next customer's?

gVisor vs Kata Containers - Isolation Models Compared