# Kamaji and `externalClusterReference` usage This document explains how to use **Kamaji's `externalClusterReference`** together with **Cluster API (CAPI)** to run Kubernetes control planes on an **external cluster**, while managing worker nodes from a management cluster. It assumes the use of the KubeVirt infrastructure provider for ease of deployment and local testing. --- ## High-level Architecture The following setup operates on **two Kubernetes clusters**: - **Management cluster** – runs Cluster API controllers and the Kamaji control-plane provider, and manages cluster lifecycle and topology. - **External cluster** - runs Kamaji, hosts the Kubernetes control plane components and receives control plane workloads via Kamaji --- ## Prerequisites - `docker` - `kind` - `kubectl` - `clusterctl` - `helm` --- ## Step 1: Create the KIND clusters Create the **management** cluster: ```bash kind create cluster --name management ``` Create the **external** cluster that will host control planes: ```bash kind create cluster --name external ``` Verify contexts: ```bash kubectl config get-contexts ``` --- ## Step 2: Initialize Cluster API controllers Switch to the management cluster: ```bash kubectl config use-context kind-management ``` Enable ClusterClass support and initialize Cluster API with Kamaji and KubeVirt: ```bash export CLUSTER_TOPOLOGY=true clusterctl init \ --core cluster-api \ --bootstrap kubeadm \ --infrastructure kubevirt \ --control-plane kamaji ``` --- ## Step 3: Enable Kamaji external cluster feature gates Patch the Kamaji controller to enable `externalClusterReference`: ```bash kubectl -n kamaji-system patch deployment capi-kamaji-controller-manager \ --type='json' \ -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/args/1", "value": "--feature-gates=ExternalClusterReference=true,ExternalClusterReferenceCrossNamespace=true" } ]' ``` --- ## Step 4: Install KubeVirt Fetch the latest stable KubeVirt version and install: ```bash export VERSION=$(curl -s "https://storage.googleapis.com/kubevirt-prow/release/kubevirt/kubevirt/stable.txt") kubectl apply -f "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-operator.yaml" kubectl apply -f "https://github.com/kubevirt/kubevirt/releases/download/${VERSION}/kubevirt-cr.yaml" ``` Enable emulation (optional, if virtualization is not supported): ```bash kubectl -n kubevirt patch kubevirt kubevirt \ --type=merge \ --patch '{"spec":{"configuration":{"developerConfiguration":{"useEmulation":true}}}}' ``` --- ## Step 5: Prepare kubeconfig for the external cluster Retrieve the external cluster control-plane address: ```bash EXT_CP_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "external-control-plane") ``` Export and rewrite the kubeconfig: ```bash kubectl --context kind-external config view --raw --minify --flatten > kind-external.kubeconfig ``` Replace the API endpoint with the cluster IP, required for cross-cluster access from the management cluster: ```bash bash -c "sed -i -E 's#https://[^:]+:[0-9]+#https://$EXT_CP_IP:6443#g' kind-external.kubeconfig" ``` Create the kubeconfig secret in the management cluster: ```bash kubectl -n default create secret generic kind-external-kubeconfig \ --from-file=kubeconfig=kind-external.kubeconfig ``` --- ## Step 6: Install Kamaji and dependencies on the external cluster Switch context: ```bash kubectl config use-context kind-external ``` Install cert-manager: ```bash helm upgrade --install cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --set installCRDs=true ``` Install Kamaji: ```bash helm upgrade --install kamaji clastix/kamaji \ --namespace kamaji-system \ --create-namespace \ --set 'resources=null' \ --version 0.0.0+latest ``` Install MetalLB: ```bash kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.15.3/config/manifests/metallb-native.yaml ``` Configure MetalLB IP address pool: ```bash SUBNET=$(docker network inspect kind | jq -r '.[0].IPAM.Config[] | select(.Subnet | test(":") | not) | .Subnet' | head -n1) NET_PREFIX=$(echo "$SUBNET" | cut -d/ -f1 | awk -F. '{print $1"."$2}') kubectl apply -f - < demo-external.kubeconfig KUBECONFIG=./demo-external.kubeconfig kubectl get nodes ``` --- ## Clean up Delete Kind clusters: ```bash kind delete cluster --name management kind delete cluster --name external ``` --- ## Summary Using `externalClusterReference` with Kamaji and Cluster API enables: - Hosted Kubernetes control planes on remote clusters - Strong separation of concerns - Multi-cluster management patterns - Clean integration with ClusterClass