vCluster Cheat Sheet
Overview
vCluster creates fully functional virtual Kubernetes clusters that run inside namespaces of a host cluster. Each virtual cluster has its own API server, control plane, and syncer component but shares the underlying host cluster’s compute resources and worker nodes. This provides strong multi-tenancy isolation — each tenant gets their own cluster experience with full admin access, custom CRDs, and independent RBAC — without the overhead of provisioning separate physical clusters.
vCluster is particularly valuable for development environments, CI/CD pipelines, testing, and multi-tenant platforms where teams need isolated Kubernetes environments that can be created and destroyed in seconds. Virtual clusters support all standard Kubernetes operations including Helm installs, CRD management, and admission webhooks, while the host cluster administrator maintains control over resource quotas and network policies at the namespace level.
Installation
CLI Installation
# macOS
brew install loft-sh/tap/vcluster
# Linux
curl -L -o vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-linux-amd64"
chmod +x vcluster
sudo mv vcluster /usr/local/bin/
# Windows
scoop install vcluster
# Verify
vcluster --version
Helm Installation
# Add Loft Helm repo
helm repo add loft https://charts.loft.sh
helm repo update
# Install vCluster operator (optional, for platform mode)
helm install vcluster-platform loft/vcluster-platform \
--namespace vcluster-platform \
--create-namespace
Core Commands
Creating Virtual Clusters
# Create a basic vCluster
vcluster create my-vcluster
# Create in specific namespace
vcluster create dev-cluster --namespace team-alpha
# Create with specific K8s distribution
vcluster create my-vcluster --distro k8s # Full k8s (default)
vcluster create my-vcluster --distro k3s # Lightweight k3s
vcluster create my-vcluster --distro k0s # k0s distribution
vcluster create my-vcluster --distro eks # EKS compatible
# Create with custom values
vcluster create staging --values vcluster-values.yaml
# Create and connect immediately
vcluster create dev-env --connect
# Create with specific Kubernetes version
vcluster create test --kubernetes-version v1.29.0
# Create with resource limits
vcluster create constrained \
--set syncer.resources.limits.cpu=500m \
--set syncer.resources.limits.memory=512Mi
Connecting and Managing
# Connect to a virtual cluster (updates kubeconfig)
vcluster connect my-vcluster
# Connect with specific namespace
vcluster connect my-vcluster --namespace team-alpha
# Connect and update specific kubeconfig
vcluster connect my-vcluster --update-current=false --kube-config ./vcluster-kubeconfig.yaml
# List all virtual clusters
vcluster list
# List across all namespaces
vcluster list --all-namespaces
# Disconnect (restore original kubeconfig context)
vcluster disconnect
# Pause a virtual cluster (saves resources)
vcluster pause my-vcluster
# Resume a paused virtual cluster
vcluster resume my-vcluster
# Delete a virtual cluster
vcluster delete my-vcluster
vcluster delete my-vcluster --namespace team-alpha
# Delete and clean up all resources
vcluster delete my-vcluster --delete-namespace
Working Inside a vCluster
# After connecting, use kubectl normally
vcluster connect dev-cluster
# Deploy applications
kubectl create namespace app
kubectl apply -f deployment.yaml -n app
# Install Helm charts
helm install nginx ingress-nginx/ingress-nginx -n ingress
# Create CRDs (isolated from host)
kubectl apply -f custom-crd.yaml
# Full cluster admin access
kubectl get nodes # Shows synced nodes from host
kubectl get namespaces # Independent namespace list
kubectl get crds # Independent CRD list
# Check cluster info
kubectl cluster-info
Configuration
Values File
# vcluster-values.yaml
# Syncer configuration
sync:
# Sync real nodes into the vCluster
nodes:
enabled: true
syncAllNodes: true
# Sync persistent volumes
persistentvolumes:
enabled: true
# Sync ingresses to host
ingresses:
enabled: true
# Sync network policies
networkpolicies:
enabled: true
# Sync storage classes from host
storageclasses:
enabled: true
# Control plane configuration
controlPlane:
distro:
k8s:
enabled: true
apiServer:
extraArgs:
- "--audit-log-path=/var/log/audit.log"
image:
tag: "v1.29.0"
statefulSet:
resources:
limits:
cpu: "1"
memory: 2Gi
requests:
cpu: 200m
memory: 256Mi
# Isolation and security
policies:
resourceQuota:
enabled: true
quota:
requests.cpu: "10"
requests.memory: 20Gi
limits.cpu: "20"
limits.memory: 40Gi
pods: "100"
services: "20"
persistentvolumeclaims: "10"
limitRange:
enabled: true
default:
cpu: 500m
memory: 512Mi
defaultRequest:
cpu: 100m
memory: 128Mi
# Networking
networking:
replicateServices:
fromHost:
- from: monitoring/prometheus
to: monitoring/prometheus
toHost:
- from: default/my-service
to: team-alpha/vcluster-service
# Storage
storage:
persistence: true
size: 5Gi
Helm-Based Creation
# Create using Helm directly
helm install my-vcluster loft/vcluster \
--namespace team-alpha \
--create-namespace \
--values vcluster-values.yaml \
--set syncer.extraArgs="{--tls-san=my-vcluster.example.com}"
# Upgrade vCluster configuration
helm upgrade my-vcluster loft/vcluster \
--namespace team-alpha \
--values vcluster-values.yaml
# Template to see what will be created
helm template my-vcluster loft/vcluster \
--namespace team-alpha \
--values vcluster-values.yaml
Advanced Usage
CI/CD Integration
#!/bin/bash
# ci-vcluster.sh — Ephemeral vCluster for CI/CD testing
set -euo pipefail
CLUSTER_NAME="ci-${CI_PIPELINE_ID:-$(date +%s)}"
NAMESPACE="ci-environments"
cleanup() {
echo "Cleaning up vCluster: $CLUSTER_NAME"
vcluster delete "$CLUSTER_NAME" --namespace "$NAMESPACE" || true
}
trap cleanup EXIT
# Create ephemeral cluster
echo "Creating vCluster: $CLUSTER_NAME"
vcluster create "$CLUSTER_NAME" \
--namespace "$NAMESPACE" \
--connect=false \
--set syncer.resources.limits.cpu=500m \
--set syncer.resources.limits.memory=1Gi
# Connect and get kubeconfig
vcluster connect "$CLUSTER_NAME" \
--namespace "$NAMESPACE" \
--update-current=false \
--kube-config /tmp/vcluster-kubeconfig.yaml
export KUBECONFIG=/tmp/vcluster-kubeconfig.yaml
# Deploy and test
kubectl apply -f manifests/
kubectl wait --for=condition=Ready pods --all --timeout=120s
./run-integration-tests.sh
echo "Tests completed. Cleaning up."
Multi-Tenant Platform
# platform-template.yaml — Template for tenant clusters
apiVersion: management.loft.sh/v1
kind: VirtualClusterTemplate
metadata:
name: team-cluster
spec:
template:
metadata: {}
instanceTemplate:
metadata:
labels:
managed-by: platform-team
helmRelease:
values: |
sync:
ingresses:
enabled: true
networkpolicies:
enabled: true
policies:
resourceQuota:
enabled: true
quota:
requests.cpu: "8"
requests.memory: 16Gi
pods: "50"
limitRange:
enabled: true
default:
cpu: 500m
memory: 512Mi
Exposing vCluster Externally
# Expose via LoadBalancer
vcluster create external-cluster \
--set controlPlane.service.type=LoadBalancer \
--set syncer.extraArgs="{--tls-san=vcluster.example.com}"
# Expose via Ingress
vcluster create external-cluster \
--set controlPlane.ingress.enabled=true \
--set controlPlane.ingress.host=vcluster.example.com
# Get external kubeconfig
vcluster connect external-cluster \
--server=https://vcluster.example.com \
--kube-config ./external-kubeconfig.yaml
Sleep Mode (Auto-Pause Idle Clusters)
# Create with auto-sleep after 30 minutes of inactivity
vcluster create dev-env \
--set policies.autoSleep.afterInactivity=1800
# Or via values file
# policies:
# autoSleep:
# afterInactivity: 1800 # seconds
# autoWakeup: true
Troubleshooting
| Issue | Cause | Solution |
|---|---|---|
| vCluster pods CrashLoopBackOff | Insufficient resources on host | Increase syncer resource limits in values |
| Cannot connect to vCluster | Port-forward not established | Run vcluster connect again or check host connectivity |
| Pods not scheduling in vCluster | Host namespace resource quota exceeded | Increase host namespace quota or add more nodes |
| Services not accessible | Service sync not enabled | Enable sync.services in values file |
| PVC not provisioning | StorageClass sync disabled | Enable sync.storageclasses.enabled: true |
| CRDs not working | CRD sync not configured | CRDs are isolated by default; this is expected behavior |
| Ingress not routing | Ingress sync not enabled | Enable sync.ingresses.enabled: true |
| Node list empty | Node sync disabled | Enable sync.nodes.enabled: true |
# Debug vCluster syncer logs
kubectl logs -n team-alpha -l app=vcluster,release=my-vcluster -c syncer --tail=50
# Check vCluster status
vcluster list
kubectl get pods -n team-alpha -l app=vcluster
# Debug host-side resources
kubectl get pods -n team-alpha
kubectl get events -n team-alpha --sort-by='.lastTimestamp'
# Check syncer connectivity
kubectl exec -n team-alpha deploy/my-vcluster -- cat /tmp/syncer.log
# Force reconnect
vcluster disconnect
vcluster connect my-vcluster --namespace team-alpha