Skip to main content

Architecture

vNode wraps each pod in a lightweight sandbox that acts as a minimal host environment. The workload sees a normal Linux environment. The host sees an unprivileged process. No hypervisor or guest kernel is involved, so containers run at native speed.

vNode achieves isolation through three kernel-level mechanisms: Linux user namespaces, FUSE-based filesystem virtualization, and targeted seccomp filtering. These prevent a process inside a vNode from accessing other tenants' files, processes, or hardware information. This protection holds even after a container escape.

Because vNode doesn't use virtualization technologies like KVM or Hyper-V, it adds no meaningful overhead. Workloads run at near-native speed.


Pod running inside a vNode sandbox on a Kubernetes nodeKubelet calls vnode-manager, which launches a pod inside a vNode sandbox on the Kubernetes node.Kubernetes NodeKubeletvnode-managervNodePod

vNode places a pod inside a sandbox managed by vnode-manager on the Kubernetes node.


Namespace layers

vNode adds a set of Linux namespace layers between the pod and the host node. A single vNode can be shared across multiple pods in the same namespace. This is useful when those pods belong to the same tenant, for example all pods inside a vCluster tenant cluster. Privileged workloads like Prometheus or Fluentd can only see pods inside their own vNode, not the host node or other tenants' workloads.

A pod can safely use features like hostPID, hostPaths, hostNetwork, and Docker-in-Docker inside a vNode. These features are scoped to the vNode rather than the host node, so they don't grant additional capabilities on the actual host.

vNode namespace layersUser, network, process, and mount namespaces are scoped differently across container, pod sandbox, vNode, and host layers.UserNetworkProcessMountContainerPod sandboxvNodeHostrootrootvNode-scopedvNode-scopedvNode-scoped

vNode scopes user, network, process, and mount namespaces between the pod sandbox and host.

Isolation granularity

vNode supports two isolation modes.

Per-namespace mode (default): One vNode runs per namespace per node. Pods in the same namespace share a PID namespace inside the vNode. This is the right choice when namespace boundaries align with tenant boundaries, for example when using vCluster, where all pods in a namespace belong to the same tenant.

Per-pod mode: Every pod gets its own isolated vNode. Enable this by setting the VNODE_PER_POD=true environment variable on the DaemonSet. Use this when pods from different users or builds share a namespace, for example in CI/CD environments. The trade-off is higher per-node memory overhead.

Startup sequence

When the vNode DaemonSet starts on a node, it runs the following steps in order:

vNode startup sequenceSix startup steps from preflight checks through the ready manager proxy.1. Preflight checksKernel 6.1+, cgroup v2,containerd running2. System preparationRemount /sys and removeconflicting bind mounts3. ContainerdRegister RuntimeClassesvnode and launcher4. AppArmor setupLoad profile and injectFUSE mount rule5. CNI setupCreate vnode-cni symlinkand write configuration6. Manager proxyStart proxy, ready forvNode workloadsDaemonSet is ready to accept workloads

The vNode DaemonSet prepares the node before accepting sandboxed workloads.

  1. Preflight checks — verifies kernel version (6.1 or later), cgroup v2, and a running containerd daemon
  2. System preparation — remounts /sys read-write and removes bind mounts that would interfere with vNode pods
  3. Containerd configuration — registers the vnode and vnode-launcher runtime classes with containerd
  4. AppArmor setup — loads the vnode-default AppArmor profile and injects the FUSE mount rule into the fusermount3 profile
  5. CNI setup — creates the vnode-cni symlink and writes the CNI configuration
  6. Manager proxy — starts the vNode manager proxy, which is ready to accept workloads

Components

vNode runtime component relationshipsTwo flows show how vNode launches the sandbox and then launches a workload inside that sandbox.Launch vNodeLaunch workload within vNodeHost nodeHost nodevNodeKubeletcontainerdvnode-managervnode-containerd-shim-runc-v2vNode podCNI(host plugin)vnode-cniKubeletcontainerdvnode-managerCNI(host plugin)vnode-cnivnode-containerd-shim-runc-v2vNode CNI(service mesh)vNode workload pod

vNode runtime components coordinate sandbox launch and workload launch inside the vNode.

The vNode runtime consists of the following components.

vNode Manager

vnode-manager is the main binary. Like busybox, it's a multi-call binary that serves three roles:

  • CNI plugin (vnode-cni): Called by containerd to remount the network namespace into the vNode user namespace. It runs the vNode CNI after the host CNI finishes.
  • Containerd shim plugin (containerd-shim-vnode-v2): Called by containerd to return the socket path of the vnode-manager.
  • Manager service (vnode-manager): Coordinates the vNode runtime. Provides custom /proc and /sys filesystems via FUSE, intercepts syscalls via the seccomp filter, manages the vnode shim, and handles UID/GID mappings.

vNode Init

vnode-init runs as PID 1 inside each vNode. It reaps zombie containerd-shim processes, keeping the vNode clean even across containerd upgrades.

vNode RunC

vnode-runc is a fork of RunC that starts vNode containers:

containerd → vnode-manager → vnode-containerd-shim-runc-v2 → vnode-runc

Compared to upstream RunC, vnode-runc integrates the vNode manager directly, fixes Linux user namespace issues, and requires cgroup v2.

vNode Containerd Shim

vnode-containerd-shim-runc-v2 spins up new vNodes:

containerd → vnode-manager → vnode-containerd-shim-runc-v2 → vnode-runc

It handles ID-mapped mounts and sets up FUSE, seccomp, and the vNode manager API for each new vNode.

vNode Utils

vnode-utils handles supporting operations: network namespace setup within a user namespace, bind-path operations between the host and vNode, directory creation, and file copying into a vNode.