Skip to main content

Getting started

vNode is a tenant isolation container runtime that provides strong isolation between workloads using Linux user namespaces and seccomp filters. It runs in Kubernetes environments and supports privileged workloads such as Docker-in-Docker and Kubernetes-in-Kubernetes. For more details, see the vNode architecture.

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 each pod inside an isolated sandbox on the Kubernetes node.

Before you begin

  • An existing vCluster Platform installation.
  • A license plan that includes vNode. To verify your plan, navigate to Platform Config → License and Billing in the platform. If vNode is not listed, contact support@vcluster.com.
  • A valid platform access key. Not required when deploying vNode inside a Tenant Cluster.
  • A Kubernetes cluster meeting the system requirements — Linux kernel 6.1+, containerd 1.7 or 2.0, Kubernetes 1.24+.

Set your environment variables

Modify the following with your specific values to replace them across the whole page:
# Platform host
PLATFORM_HOST=https://platform-your-domain.com

# Platform access key
PLATFORM_ACCESS_KEY=your-access-key
Platform running in the same cluster

If the vCluster Platform is deployed in the same cluster as vNode, set PLATFORM_HOST to the platform Service's ClusterIP, not its cluster-internal DNS name (for example, https://loft.vcluster-platform).

The vnode-manager enters the node's network namespace to configure containerd. From that namespace it uses the node's DNS resolver, which cannot resolve cluster-internal service names. kube-proxy does route ClusterIP traffic for node-originated connections, so the ClusterIP address works correctly.

Find the ClusterIP of the platform Service:

kubectl get svc loft -n vcluster-platform -o jsonpath='{.spec.clusterIP}'

Then set PLATFORM_HOST=https://<clusterIP>:443.

If a cluster-internal DNS name is used instead, the manager logs dial tcp: lookup ... no such host, containerd is never reconfigured, and tenant pods fail with FailedCreatePodSandbox: no runtime for "vnode" is configured.

If you manage vNode with Argo CD, Flux, or another GitOps tool, store the access key in a Kubernetes secret instead of your values file. See Provide the platform access key via a secret.

Install vNode

helm upgrade --install vnode-runtime vnode-runtime -n vnode-runtime \
--repo https://charts.loft.sh --create-namespace \
--set "config.platform.host=https://platform-your-domain.com" \
--set "config.platform.accessKey=your-access-key"

# Add the following only if your platform uses a self-signed certificate:
# --set "config.platform.insecure=true"

For cluster creation steps and platform-specific configuration, see Installation.

Verify your installation

Modify the following with your specific values to replace them across the whole page:

Create a privileged test pod using the vNode runtime:

echo "apiVersion: v1
kind: Pod
metadata:
name: vnode-test
spec:
runtimeClassName: vnode
hostPID: true
terminationGracePeriodSeconds: 1
containers:
- image: ubuntu:jammy
name: vnode-test
command: ['tail', '-f', '/dev/null']
securityContext:
privileged: true" | kubectl apply -f -

kubectl wait --for=condition=ready pod vnode-test

Verify UID remapping

User namespace remapping is the observable proof that vNode's tenant isolation is active. Read /proc/self/uid_map inside the pod:

kubectl exec vnode-test -- cat /proc/self/uid_map

A pod using the vNode runtime shows root remapped to a high unprivileged host UID:

0 589824 65536

Container UID 0 maps to host UID 589824. Even if a process escapes the container boundary, it has no host privileges.

A pod not using the vNode runtime shows an identity map:

0 0 4294967295

UID 0 inside the container is UID 0 on the host. If you see this output on a pod that should be using vNode, check that containerd was reconfigured successfully (see the ClusterIP note in Set your environment variables).

Verify process isolation

Within the test pod, ps -ef shows only the pod's own processes — not those of other containers or the host:

kubectl exec -it vnode-test -- ps -ef --forest
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 10:20 ? 00:00:00 /var/lib/vnode/bin/vnode-init
root 53 1 0 10:20 ? 00:00:00 /var/lib/vnode/bin/vnode-containerd-shim-runc-v
65535 75 53 0 10:20 ? 00:00:00 \_ /pause
root 185 53 0 10:20 ? 00:00:00 \_ tail -f /dev/null

Without vNode, a privileged pod with hostPID: true would see all processes on the host.