logo

Cheatsheet - gVisor

runsc

runsc (run Sandboxed Container) is the OCI-compliant executable used to interact with the gVisor sandbox. It functions similarly to runc but wraps the process in a secure user-space kernel (the Sentry).

Installation & Environment

Subcommand Description Example / Usage
install Configures Docker to use runsc. Updates /etc/docker/daemon.json. sudo runsc install
version Shows the version, commit, and build info. runsc version
flags Lists all global flags available to the runsc binary. runsc flags
capabilities Lists the Linux capabilities supported by the sandbox. runsc capabilities

Lifecycle Management

These commands follow the OCI runtime specification for managing container states.

Subcommand Description Command Example
run Creates and starts a container (bundle must exist). runsc run <container-id>
create Creates a container but does not start it (waiting for start). runsc create <id>
start Starts a container previously created by create. runsc start <id>
kill Sends a signal (default SIGTERM) to the container. runsc kill <id> SIGKILL
delete Deletes any resources held by the container (must be stopped). runsc delete <id>
pause Suspends all processes inside the container. runsc pause <id>
resume Resumes processes inside a paused container. runsc resume <id>

Execution & Inspection

Use these to see what is happening inside the sandbox.

Subcommand Description Command Example
list Lists containers started by runsc and their status. runsc list
ps Lists processes running inside a specific container. runsc ps <container-id>
exec Executes a new process inside an existing container. runsc exec <id> /bin/bash
state Outputs the state (JSON) of a container. runsc state <id>
events Displays container stats (CPU, Memory) in a stream. runsc events <id>

Debugging & Advanced Diagnostics

These are critical for troubleshooting syscall failures or performance bottlenecks.

Subcommand Description Notes
debug Shows the Sentry's internal state (for developer use). Requires --debug flag.
trace Manages "session" traces (e.g., syscall tracing). runsc trace metadata
boot Manual internal command to start a sandbox. Used by runsc internally.
do Fast Testing: Runs a process in a sandbox without a full OCI bundle. runsc do /bin/ls

runsc trace

The runsc trace command suite is used to interact with gVisor's internal Trace Sessions. Unlike standard strace, which monitors syscalls from the host side, runsc trace allows you to hook into the Sentry (the gVisor kernel) to capture detailed execution data with lower overhead and higher detail.

runsc trace Subcommands:

Subcommand Description Example
list Lists all available trace points (events) gVisor can track. runsc trace list
metadata Shows schema information for trace points (fields, types). runsc trace metadata
create Starts a new tracing session based on a configuration file. runsc trace create --config=cfg.json <session-id>
delete Stops and removes an active tracing session. runsc trace delete <session-id>
procfs (Internal/Diagnostic) Displays a virtual directory tree of tracing sessions. runsc trace procfs

Examples

# To find the root folder:
$ ps aux | grep runsc
# look for --root flag

# For Docker created containers:
$ sudo runsc --root /var/run/docker/runtime-runc/moby trace procfs CONTAINER_ID

runsc ps vs runsc trace procfs

While both commands provide a way to "look inside" a running gVisor sandbox, they operate at completely different layers of the system.

Quick Comparison Table:

Feature runsc ps runsc trace procfs
Primary Goal List Application Processes. Inspect Tracing Infrastructure.
Perspective What is the container doing? What is the gVisor kernel monitoring?
Output Type Tabular (PID, Command, etc.). Virtual Directory Tree (Files/Paths).
Standard Part of OCI Runtime Spec. gVisor-specific diagnostic tool.
Analogy Looking at a "Task Manager" for the app. Looking at the "Settings" of a security camera.

Essential Global Flags

These flags must be placed before the subcommand (e.g., runsc --debug run ...).

  • --debug: Enables debug logging.
  • --debug-log=<path>: Directs logs to a file or directory. gVisor logs are very verbose and categorized by component (Sentry, Gofer).
  • --platform=<name>: Selects the syscall interception method.
    • systrap (Default): Modern, signal-based interception.
    • kvm: Hardware virtualization (requires /dev/kvm).
    • ptrace: Universal but slow.
  • --network=<type>:
    • sandbox (Default): Uses gVisor’s internal Go network stack (Isolated).
    • host: Uses the host network stack (Faster, but less secure).
  • --rootless: Allows running containers without root privileges.
  • --profile-cpu=<file>: Captures a Go CPU profile for performance analysis.

The "runsc do" Shortcut

One of the most useful commands for quick testing without needing Docker or a config.json bundle:

# Run a shell inside a gVisor sandbox immediately
runsc do /bin/sh

# Check the kernel version inside the sandbox
runsc do uname -a

Troubleshooting Common Errors

  • "Read-only file system": gVisor is strict about mounts. Ensure your mount points in config.json are correct.
  • "Function not implemented": The application called a syscall gVisor doesn't support yet.
    • Fix: Run with --debug --debug-log=/tmp/logs/ and search for "unsupported syscall".
  • Performance Issues:
    • Fix: Try switching to the KVM platform: runsc --platform=kvm run <id>.
    • Fix: If using heavy networking, test with --network=host to see if the Go netstack is the bottleneck.

Installation (Quick Start)

# Download the binary
curl -LO https://storage.googleapis.com/gvisor/releases/release/latest/x86_64/runsc
curl -LO https://storage.googleapis.com/gvisor/releases/release/latest/x86_64/runsc.sha256

# Verify and install
sha256sum -c runsc.sha256
chmod +x runsc
sudo mv runsc /usr/local/bin/

Docker Configuration

To use gVisor with Docker, you must register runsc as a runtime.

Update /etc/docker/daemon.json:

{
  "runtimes": {
    "runsc": {
      "path": "/usr/local/bin/runsc"
    }
  }
}

Restart Docker:

sudo systemctl restart docker

Running a container with gVisor:

docker run --runtime=runsc -it ubuntu /bin/bash

containerd Configuration

To apply global configuration changes to all gVisor sandboxes managed by containerd, you need to modify the containerd configuration file (typically located at /etc/containerd/config.toml).

There are two primary ways to do this: by passing flags directly in the containerd config, or by pointing gVisor to a dedicated global configuration file.

Method 1: Direct Configuration in config.toml (Recommended)

This method involves adding runtime_args to the specific runtime handler used for gVisor. Open the config file: /etc/containerd/config.toml

Locate the runsc runtime section. If it doesn't exist, you will need to create it. Add your desired flags (like changing the platform to KVM) inside the runtime_args array.

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
  runtime_type = "io.containerd.runsc.v1"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc.options]
    # These args apply to every gVisor container
    runtime_args = [
      "--platform=kvm",
      "--network=sandbox",
      "--debug",
      "--debug-log=/var/log/runsc/"
    ]

Restart containerd:

sudo systemctl restart containerd

Method 2: Using an External gVisor Config File

If you want to keep your gVisor settings separate from your containerd settings, you can create a dedicated gVisor JSON configuration file and tell containerd to use it.

  1. Create the gVisor config file (e.g., /etc/gvisor/config.json):

    {
      "platform": "kvm",
      "network": "sandbox",
      "debug": true,
      "debug-log": "/var/log/runsc/"
    }
    
  2. Point containerd to this file in /etc/containerd/config.toml:

    [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc]
      runtime_type = "io.containerd.runsc.v1"
      [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runsc.options]
        runtime_args = ["--config=/etc/gvisor/config.json"]
    
  3. Restart containerd:

    sudo systemctl restart containerd
    

Common Configuration Scenarios

Here are the most common settings people change globally:

1. Enable KVM (Hardware Acceleration)

If your host supports virtualization, KVM is significantly faster than the default systrap.

  • Flag: --platform=kvm
  • Note: Ensure /dev/kvm is accessible.

2. Change Networking Stack

By default, gVisor uses a Go-based userspace network stack (sandbox).

  • For Isolation: --network=sandbox (Default)
  • For Performance: --network=host (Warning: Reduces security as the sandbox shares the host network namespace).

3. Global Debugging

If you are troubleshooting why containers won't start:

  • Flags: --debug, --debug-log=/var/log/runsc/
  • Note: Ensure the directory exists and is writable by the user running containerd.

How to verify the changes applied?

After restarting containerd, start a new gVisor container and check the runsc logs or the container's environment.

If you enabled KVM, you can verify it by looking at the logs:

grep "Platform: KVM" /var/log/runsc/runsc.log.*

Or check the kernel name from inside the container:

kubectl run -it --rm --restart=Never --overrides='{"spec":{"runtimeClassName":"gvisor"}}' test-pod --image=alpine -- uname -a

Kubernetes Integration (RuntimeClass)

  1. Create the RuntimeClass:
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
  1. Use it in a Pod Spec:
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  runtimeClassName: gvisor
  containers:
    - name: nginx
      image: nginx

Selection of Platforms (--platform)

The platform determines how gVisor intercepts syscalls.

Platform Best For Description
KVM Performance Uses hardware virtualization (VT-x/AMD-V). Fast, but requires nested virtualization if running in a VM.
ptrace Compatibility Works everywhere (even inside restricted VMs). Slower due to context switching.
systrap Modern Linux Uses a specialized signal-based approach. Often the default for newer versions.

Changing the platform in Docker: Modify /etc/docker/daemon.json:

"runsc": {
    "path": "/usr/local/bin/runsc",
    "runtimeArgs": ["--platform=kvm"]
}

Verification: Is it working?

To check if a container is actually running inside gVisor, check the kernel name from within the container:

docker run --runtime=runsc --rm alpine uname -a
# Output should mention "gVisor" instead of "Linux version..."

Check the dmesg output (it will be simulated):

docker run --runtime=runsc --rm alpine dmesg

Troubleshooting & Performance

  • Networking: gVisor has its own network stack (Netstack). If performance is an issue, you can use --network=host, but it reduces isolation.
  • Filesystem: Use --fsdiscard-mounts for better performance on ephemeral mounts.
  • Unsupported Syscalls: If an app fails, check runsc logs. gVisor implements ~300+ Linux syscalls, but some niche ones (or specific /proc / /sys paths) may be missing.
  • Debugging Logs:
    # Enable debug logging in daemon.json
    "runtimeArgs": ["--debug", "--debug-log=/tmp/runsc.log"]