Containers share the host kernel. That property explains much of their lightness, and it also sets their ceiling in multi-tenant environments where trust between workloads is low.

Google built gVisor precisely to raise that ceiling. It inserts a kernel written in Go between the container process and the real host kernel. That kernel reduces the exposed system-call surface and offers an isolation level between the traditional container and the lightweight virtual machine.

Key takeaways

  • gVisor implements the OCI-compatible runsc runtime that replaces runc by interposing a user-space kernel called Sentry.

  • The systrap mode, released in 2023 and made the default the same year, is the one to use today: good performance, portable, no special hardware requirements.

  • For CPU workloads the overhead sits in the low single digits. For syscall-heavy workloads (Redis, databases with constant writes), independent benchmarks measure a 50 % to over 100 % impact.

  • Integrating gVisor into an existing Kubernetes cluster requires installing runsc and declaring a RuntimeClass; other pods keep using runc.

  • Makes sense for multi-tenant workloads, serverless functions, and untrusted-code execution; not for heavy databases or high-IOPS loads.

What gVisor is and why it was built

gVisor implements an OCI-compatible runtime called runsc that replaces runc. The decisive difference is that runsc doesn’t let the container process talk to the host kernel directly. Instead, a component called Sentry intercepts those calls and responds to most of them itself. Sentry is a Linux kernel reimplemented in Go in user space, and it talks to the host only when unavoidable, always through a narrow perimeter.

The result is that a kernel exploit that would normally escalate from container to host has to traverse Sentry first, which is much smaller and written in a memory-safe language. Google open-sourced the code in 2018 and uses it in production to run customer code in App Engine, Cloud Run, and Cloud Functions.

Architecture: Sentry, Gofer and platform modes

When a container starts with runsc, the runtime creates two main host processes:

  • Sentry: the user-space kernel that runs the container code.

  • Gofer: a separate process that mediates filesystem access.

The separation is deliberate: even if an attacker compromises Sentry, they still have to cross Gofer to touch disk, and neither has privileged capabilities beyond what’s strictly needed.

System-call interception uses two main modes:

  • ptrace: portable but slow, rarely used in production.

  • KVM: leverages hardware virtualization extensions and performs better than ptrace, but requires /dev/kvm.

  • systrap (the default platform since its 2023 release[1]): uses seccomp with notification filters to intercept calls without depending on KVM or ptrace. Good performance, portable, no special hardware requirements.

Important detail: Sentry doesn’t implement every Linux system call. It covers most of what a typical program needs, but obscure calls will fail if the container tries them. This is deliberate: each implemented call is potential attack surface.

Performance: where it wins and where it loses

For CPU-heavy workloads with little kernel contact, gVisor is close to a native container. The project’s own performance guide[2] explains there is no added cost to raw instruction execution, because Sentry does not emulate the CPU. An independent KubeBlocks benchmark[3] using Sysbench measured only about 4 % overhead versus runc, roughly matching Kata.

The story changes with syscall-heavy loads:

  • The same KubeBlocks benchmark measured 56 % (KVM platform) to 95 % (ptrace platform) degradation on Redis operations, and 125 % overhead on a SQLite insertion benchmark, versus 17 % for Kata.

  • Networking also has impact: gVisor ships its own Go TCP stack (netstack). Its own documentation[2] acknowledges that simple web services with little per-request work feel the overhead more than workloads that do substantial computation between calls.

The operational lesson: gVisor is a good choice for HTTP APIs with real per-request work, serverless functions, batch jobs, and untrusted user code execution. It’s a bad choice for databases with constant writes, for serving small static files at a high request rate, or for any workload whose main metric is IOPS or syscalls per second.

Comparison with Kata Containers and microVMs

The obvious comparison is with Kata Containers, which also seeks reinforced container isolation but by starting a small virtual machine using Firecracker or QEMU. The threat models are different:

  • Kata bets on the hardware barrier of the hypervisor.

  • gVisor bets on surface reduction in user space.

Kata tends to better compatibility with I/O-heavy workloads because inside the VM runs a complete Linux kernel. In contrast, gVisor tends to start faster and consume less fixed memory per container because there’s no full hypervisor to load. On Cloud Run, where cold start matters, choosing gVisor makes sense.

Firecracker alone is a different building block: strong threat model from hypervisor separation, but operating pure Firecracker implies much more orchestrator integration than runsc, which plugs into containerd with a handful of config lines.

Operation and deployment

Integrating gVisor into an existing cluster is relatively straightforward. Install runsc, configure containerd to recognize it as an alternative runtime, and use a Kubernetes RuntimeClass to mark which pods should start under it. Marked pods run with Sentry and Gofer; the rest keep using runc.

This lets you apply gVisor only to workloads that need it without imposing its I/O cost on the whole cluster. This mixed-runtime pattern fits well with the containerd with Wasm model, where multiple runtimes coexist on the same node.

runsc exports Prometheus-format metrics with CPU and memory usage, and logs integrate with the usual logging stack. Diagnosis when something fails is trickier than with runc because messages can come from Sentry, but project documentation has improved a lot and there’s an active community.

When it pays off

gVisor has a clear niche: multi-tenant workloads where isolation matters and the usage pattern is CPU-heavy and I/O-light.

  • Platforms running third-party code.

  • Serverless functions.

  • Test environments where different users share nodes.

  • Educational clusters and malware analysis labs.

In all those cases the attack-surface reduction offsets the small CPU cost. Mixing runtimes is standard practice: gVisor for part of the cluster, Kata for another, and runc for the rest, picking the barrier that best matches each workload’s trust level and performance profile. That heterogeneity is today’s mature answer to container isolation in multi-tenant environments.

Where it doesn’t pay off is in first-party workloads from an organization that trusts its own code. If all pods come from the same team through the same pipeline, the extra sandbox rarely justifies the operational cost.

Frequently asked questions

How much performance do I lose running a container under gVisor?

It depends on the workload. For CPU-heavy work with few system calls, an independent KubeBlocks benchmark using Sysbench measured only about 4 % overhead versus runc, because Sentry does not emulate the CPU. Syscall-heavy loads are a different story: 56 % (KVM platform) to 95 % (ptrace) degradation on Redis operations and 125 % on a SQLite insertion benchmark, versus 17 % for Kata.

Can I use gVisor for only some pods in my Kubernetes cluster?

Yes. Install runsc on the nodes, configure containerd to recognise it as an alternative runtime, then declare a Kubernetes RuntimeClass; only pods that reference it start with Sentry and Gofer, while the rest keep using runc. A mixed setup combines gVisor for part of the cluster, Kata for another part and runc for the rest, according to each workload's trust level and performance profile.

Which gVisor platform mode should I use: ptrace, KVM or systrap?

systrap, the default since its 2023 release. It uses seccomp with notification filters to intercept calls without depending on KVM or ptrace, with good performance, portability and no special hardware requirements. ptrace is portable but slow and rarely used in production. KVM performs better than ptrace but requires access to /dev/kvm.

Sources

  1. 2023 release
  2. performance guide
  3. KubeBlocks benchmark