Tech Blog by vClusterPress and Media Resources

vCluster Logging: Logs, JSON, Debug, and Audit

Sep 1, 2026
|
6
min Read
vCluster Logging: Logs, JSON, Debug, and Audit

This is a simple, step-by-step guide to vCluster logging and audit logs: control plane logs, JSON logs, debug logs, and Kubernetes audit logs.

Every step includes the exact commands and example output so you know what to expect. The steps work on any Kubernetes cluster (kind, k3d, EKS, GKE, AKS, and more).

What you'll do

  1. Create a tenant cluster (baseline)
  2. Read the vCluster control plane logs
  3. Switch logs to JSON
  4. Turn debug logging on/off
  5. Enable Kubernetes audit logs for the tenant API server and verify them

Before you start

You need the following before starting:

  • kubectl connected to your Control Plane Cluster
  • helm installed
  • vcluster CLI installed (Step 1)
  • vCluster Platform installed and running (Steps 3+)

Control Plane Cluster vs tenant cluster

  • Control Plane Cluster is where the vCluster pod runs (namespace <tenant-cluster-namespace>)
  • Tenant cluster is the tenant Kubernetes cluster you connect to with vcluster connect

Whenever you check pods or logs in -n <tenant-cluster-namespace>, you must be on the Control Plane Cluster context (usually after vcluster disconnect).

Placeholder values used in this guide

Commands use placeholders instead of hard-coded names. Replace these with your actual values before running:

PlaceholderExample valueDescription
<tenant-cluster-name>my-vclusterThe name of your tenant cluster
<tenant-cluster-namespace>my-vclusterNamespace on the Control Plane Cluster
<tenant-cluster-pod>my-vcluster-0The vCluster pod name

For Platform UI-created clusters, the namespace looks like loft-default-v-my-vcluster. Run kubectl get pods --all-namespaces | grep vcluster to find the exact value.

Step 1: Install the vCluster CLI

Check your CPU architecture:

uname -m

Download a matching binary (example: macOS arm64):

mkdir -p ~/bin
curl -L -o ~/bin/vcluster "https://github.com/loft-sh/vcluster/releases/latest/download/vcluster-darwin-arm64"
chmod +x ~/bin/vcluster
export PATH="$HOME/bin:$PATH"
vcluster version

Expected output:

vcluster version 0.35.1

If you are unsure which binary you installed, run which vcluster.

Step 2: Verify kubectl points to the Control Plane Cluster

kubectl cluster-info

You should see a "Kubernetes control plane is running at …" line. Make sure it is the cluster you want to run vCluster on.

Step 3: Install / start vCluster Platform

vcluster platform start \
--namespace vcluster-platform \
--values vcluster-platform.yaml

Step 4: Switch the vcluster CLI to Platform mode

vcluster use driver platform

If you skip this, vcluster create with Platform flags (like --project) may fail or behave like Helm mode.

Step 5: Create a tenant cluster

You can create a tenant cluster either via the CLI or the Platform UI. Both produce the same result.

Option A: Via CLI

vcluster create <tenant-cluster-name> \
-n <tenant-cluster-namespace> \
--project default

When prompted, choose Virtual Cluster Template (Isolated).

Option B: Via Platform UI

  1. Open the Platform UI (the URL shown after vcluster platform start)
  2. Navigate to Default Project → Tenant Clusters
  3. Click Create Tenant Cluster
  4. Select your Control Plane Cluster and worker node configuration

Create tenant cluster in the Platform UI: select Control Plane Cluster and worker node configuration

  1. Keep the default settings or adjust as needed. Set the display name, version, and backing store, then click Create Cluster

Configure the tenant cluster: set display name, version, and backing store, then click Create Cluster

The UI shows a status indicator. Wait until it shows Running, 5/5 steps completed before continuing.

Tenant cluster status showing Running: Control Plane Running, 5/5 steps completed

Confirm the pod exists on the Control Plane Cluster

After creation, the CLI often connects you to the tenant automatically. Disconnect first:

vcluster disconnect

Then check the Control Plane Cluster:

kubectl get pods -n <tenant-cluster-namespace>

You should see a pod named <tenant-cluster-name>-0.

Step 6: Stream control plane logs

kubectl logs -n <tenant-cluster-namespace> <tenant-cluster-pod> -f

Press Ctrl+C to stop.

Step 7: Switch logs to JSON

Option A (recommended): Set it permanently in vcluster.yaml

To enable JSON-formatted logs:

logging:
encoding: json

To switch back to console format, either remove the logging field or set:

logging:
encoding: console

Changing the encoding restarts the pod.

Option B: Patch via env var (temporary)

vCluster Platform controls log encoding via the LOFT_LOG_ENCODING env var. Patch the StatefulSet:

kubectl set env statefulset/<tenant-cluster-name> \
-n <tenant-cluster-namespace> \
LOFT_LOG_ENCODING=json

Stream logs again to confirm:

kubectl logs -n <tenant-cluster-namespace> <tenant-cluster-pod> -f

You should now see JSON lines.

Step 8: Enable debug logging

Turn debug on:

kubectl set env statefulset/<tenant-cluster-name> \
-n <tenant-cluster-namespace> \
DEBUG=true

View a few debug lines to confirm:

kubectl logs -n <tenant-cluster-namespace> <tenant-cluster-pod> -f \
| grep '"level":"debug"' \
| head -5

Turn debug off:

kubectl set env statefulset/<tenant-cluster-name> \
-n <tenant-cluster-namespace> \
DEBUG-

Step 9: Enable audit logging

Audit logs record every request to the tenant cluster API server, including who made it, what resource they touched, and what the result was.

Create the audit policy ConfigMap

cat > audit-policy.yaml <<'EOF'
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: Metadata
resources:
- group: ""
resources: ["secrets", "configmaps"]
- level: Request
omitStages:
- RequestReceived
EOF

kubectl create configmap audit-config \
-n <tenant-cluster-namespace> \
--from-file=audit-policy.yaml

Expected output:

configmap/audit-config created

Add audit config to vcluster.yaml and deploy

The cleanest way to enable audit logging is to declare everything in vcluster.yaml before creating the tenant cluster. vCluster handles mounting the policy file and passing the flags to the API server automatically.

cat > vcluster.yaml <<'EOF'
controlPlane:
distro:
k8s:
apiServer:
extraArgs:
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
- --audit-log-path=/dev/stdout
statefulSet:
persistence:
addVolumes:
- name: audit-policy
configMap:
name: audit-config
addVolumeMounts:
- name: audit-policy
mountPath: /etc/kubernetes
EOF

Create the tenant cluster using this config:

vcluster create <tenant-cluster-name> \
-n <tenant-cluster-namespace> \
-f vcluster.yaml \
--connect=false

Expected output:

info Create vcluster my-vcluster...
done Successfully created virtual cluster my-vcluster in namespace my-vcluster.
- Use 'vcluster connect my-vcluster --namespace my-vcluster' to access the virtual cluster

Verify the pod is running:

kubectl get pods -n <tenant-cluster-namespace>

Expected output:

NAME READY STATUS RESTARTS AGE
coredns-df8c87f55-p9j96-x-kube-system-x-my-vcluster 1/1 Running 0 24s
my-vcluster-0 1/1 Running 0 55s

Verify the audit flags are in the API server

kubectl exec -n <tenant-cluster-namespace> <tenant-cluster-pod> -c syncer -- \
ps -ef | grep kube-apiserver | tr ' ' '\n' | grep audit

Expected output:

--audit-policy-file=/etc/kubernetes/audit-policy.yaml
--audit-log-path=/dev/stdout

Trigger an audit event and verify

Connect to the tenant cluster:

vcluster connect <tenant-cluster-name> -n <tenant-cluster-namespace>

Create a test secret:

kubectl create secret generic audit-test --from-literal=password=hello123

Expected output:

secret/audit-test created

Disconnect back to the Control Plane Cluster:

vcluster disconnect

Check the logs for the audit event:

kubectl logs -n <tenant-cluster-namespace> <tenant-cluster-pod> -c syncer \
| grep "audit-test" \
| head -2

Expected output:

{"kind":"Event","apiVersion":"audit.k8s.io/v1","level":"Metadata","auditID":"349ee9d8-7d7c-41ca-ab3c-f20a6d471d2d","stage":"ResponseComplete","requestURI":"/api/v1/namespaces/default/secrets","verb":"create","user":{"username":"kubernetes-super-admin"},"objectRef":{"resource":"secrets","namespace":"default","name":"audit-test","apiVersion":"v1"},"responseStatus":{"code":201},"requestReceivedTimestamp":"2026-06-24T08:32:21.372538Z","annotations":{"authorization.k8s.io/decision":"allow"}}

The audit event shows exactly what happened: a secret called audit-test was created in the default namespace and got a 201 Created response.

Quick reference

ActionCommand
Stream logskubectl logs -n NAMESPACE POD -f
Enable JSON logs (permanent)Set logging.encoding: json in vcluster.yaml
Enable JSON logs (temporary)kubectl set env statefulset/NAME -n NAMESPACE LOFT_LOG_ENCODING=json
Debug onkubectl set env statefulset/NAME -n NAMESPACE DEBUG=true
Debug offkubectl set env statefulset/NAME -n NAMESPACE DEBUG-
Find audit eventskubectl logs -n NAMESPACE POD
Share:
Get started with the #1 tenant isolation platform.

Give your tenants the hyperscaler experience, ready in seconds.

Ready to take vCluster for a spin?

Deploy your first virtual cluster today.