Skip to content

Create Your First Cluster

This guide walks you through creating your first tenant cluster on kMetal. The tenant cluster runs as a CAPI Cluster referencing the platform-provided kubevirt-kubeadm ClusterClass — the ClusterClass handles the rest (Kamaji control plane, KubeVirt worker VMs, networking).

Prerequisites

Before creating your first cluster, ensure you have:

  • A working kMetal installation (see Install kMetal).
  • kubectl access to the under cluster.
  • A tenant namespace where you'll create the Cluster resource.
  • A MetalLB VIP allocated for the tenant control plane.
  • An OVN Subnet allocated for the tenant's worker VMs.
  • A bootstrap-server address the worker VMs can reach (typically a node on the under cluster's data network).

Step 1: Create the Cluster

Create a Cluster resource referencing the kubevirt-kubeadm ClusterClass:

# my-first-cluster.yaml
apiVersion: cluster.x-k8s.io/v1beta2
kind: Cluster
metadata:
  name: my-first-cluster
  namespace: <tenant-namespace>
spec:
  clusterNetwork:
    pods:
      cidrBlocks: ["10.200.0.0/16"]
    services:
      cidrBlocks: ["10.201.0.0/16"]
  topology:
    classRef:
      name: kubevirt-kubeadm
      namespace: kmetal-capi-providers
    version: v1.34.1
    variables:
      - name: controlPlane
        value:
          dataStoreName: default
          network:
            serviceAddress: <metallb-vip>
            serviceType: LoadBalancer
      - name: machineSize
        value: small
      - name: bootstrapConfig
        value:
          serverAddress: <bootstrap-server>
      - name: network
        value:
          subnet: <ovn-subnet-name>
    workers:
      machineDeployments:
        - class: default-worker
          name: md-0
          replicas: 2

Apply it:

kubectl apply -f my-first-cluster.yaml

Step 2: Monitor Cluster Creation

Cluster creation typically takes a few minutes (control plane comes up first; workers boot from KubeVirt DataVolumes).

# CAPI Cluster + child resources
kubectl get cluster,kamajicontrolplane,tenantcontrolplane,kubevirtcluster -n <tenant-namespace>

# Workers
kubectl get machinedeployment,machines -n <tenant-namespace>

# Kamaji control plane pods (live in the tenant namespace)
kubectl get pods -n <tenant-namespace> -l kamaji.clastix.io/name=my-first-cluster

Step 3: Access Your Cluster

Kamaji creates the admin kubeconfig as a Secret in the same namespace as the Cluster:

kubectl get secret my-first-cluster-admin-kubeconfig -n <tenant-namespace> \
  -o jsonpath='{.data.admin\.conf}' | base64 -d > my-first-cluster.kubeconfig

export KUBECONFIG=my-first-cluster.kubeconfig
kubectl get nodes

Step 4: Validate Your Cluster

Deploy a test workload:

kubectl create deployment nginx --image=nginx:alpine
kubectl expose deployment nginx --port=80

kubectl get pods,svc
kubectl run test-pod --image=busybox --rm -it -- wget -qO- nginx

Troubleshooting

If something looks stuck:

# Top-level Cluster status
kubectl describe cluster my-first-cluster -n <tenant-namespace>

# Control plane
kubectl describe kamajicontrolplane my-first-cluster -n <tenant-namespace>
kubectl get pods -n <tenant-namespace> -l kamaji.clastix.io/name=my-first-cluster

# Workers
kubectl get machines -n <tenant-namespace>
kubectl describe machine <machine-name> -n <tenant-namespace>

# Events
kubectl get events -n <tenant-namespace> --sort-by='.lastTimestamp'

For deeper troubleshooting, see:

Next Steps

Your first cluster is ready. Continue with:

For platform administrators, see the Admin Guide for configuration and operations.