Kind (laptop lab)¶
Run VirtFoundry on your machine with kind (Kubernetes in Docker). You do not need a VLAN, a managed switch, or MetalLB.
This is the path for trying the UI and a first VM. Public guest IPs on your Wi-Fi are optional and come later on this page.
What “public” means here
On a homelab with a switch, public is often a dedicated VLAN. On kind it is either off (VMs on the pod network + noVNC in the UI) or a second Docker network that only your laptop can reach. Same Helm keys either way — see Topologies — public underlay.
What you need¶
| Tool | Notes |
|---|---|
| Docker | Running |
| kind | kind version |
| kubectl + Helm 3 | |
/dev/kvm |
Linux — nested VMs are fast. Docker Desktop (macOS/Windows) usually has no KVM; use software emulation (slower). |
# Linux
test -e /dev/kvm && echo "KVM ok" || echo "No KVM — you will use emulation"
1. Create the cluster¶
Save as kind-cluster.yaml (or copy examples/kind-cluster.yaml from the chart repo).
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: virtfoundry
nodes:
- role: control-plane
extraMounts:
- hostPath: /dev/kvm
containerPath: /dev/kvm
extraPortMappings:
- containerPort: 30880
hostPort: 8080
protocol: TCP
No /dev/kvm? Delete the extraMounts block.
kind create cluster --config kind-cluster.yaml
kubectl cluster-info --context kind-virtfoundry
Kind ships a standard StorageClass (local-path). Volume snapshots will not work; use VM snapshots in the UI.
2. Platform components¶
The Helm chart does not install KubeVirt, Multus, or CDI. From a helm-charts clone:
export KUBECONFIG="${KUBECONFIG:-$HOME/.kube/config}"
./scripts/setup/multus.sh
./scripts/setup/kubevirt.sh
./scripts/setup/cdi.sh
Without KVM, turn on emulation after KubeVirt is Available:
kubectl -n kubevirt patch kubevirt kubevirt --type merge -p \
'{"spec":{"configuration":{"developerConfiguration":{"useEmulation":true}}}}'
Wait until kubectl get kubevirt -n kubevirt shows Available.
3. Install VirtFoundry (public off)¶
Overlay values-kind.yaml: NodePort 30880 (mapped to host 8080), public.enabled: false.
curl -fsSL https://raw.githubusercontent.com/virtfoundry/helm-charts/main/charts/virtfoundry/values-kind.yaml \
-o values-kind.yaml
helm repo add virtfoundry https://virtfoundry.github.io/helm-charts
helm repo update
helm install virtfoundry virtfoundry/virtfoundry \
--version 0.5.0 \
--namespace virtfoundry-system --create-namespace \
-f values-kind.yaml \
--set secrets.rootPassword='change-me' \
--set secrets.jwtSecret='change-me-long-random'
Open http://127.0.0.1:8080 — user root, password change-me.
Deploy a container-disk VM (Templates → small offering → Console). The guest has a pod IP only; you reach it through noVNC, not from your LAN.
Isolated VPCs still work: bridge-keeper creates virtfoundry-br0 inside the kind node. That L2 never leaves Docker.
4. Optional — local “public” IPs (still no VLAN)¶
Use this when you want a guest address you can ping from the same laptop, without a switch.
Kubernetes inside kind uses eth0 on the kind Docker network. Never set that as public.bridge.uplink — bridge-keeper would steal the node IP and the cluster dies.
Add a second Docker network (this is the kind equivalent of a second NIC on a house LAN):
docker network create --driver bridge \
--subnet 10.0.50.0/24 --gateway 10.0.50.1 \
virtfoundry-pub
docker network connect virtfoundry-pub virtfoundry-control-plane
docker exec virtfoundry-control-plane ip -br addr
# eth0 = kind (kubelet) ← do not touch
# eth1 = 10.0.50.x ← public uplink
If the extra NIC is not eth1, use the name you see.
# values-kind-public.yaml — merge with values-kind.yaml
platform:
networking:
public:
enabled: true
cidr: 10.0.50.0/24
gateway: 10.0.50.1 # Docker bridge on your laptop
dns:
- 10.0.50.1
ipPool:
start: 10.0.50.10
end: 10.0.50.99
bridge:
name: vf-pub0
uplink: eth1 # extra NIC, not eth0
address: 10.0.50.2/24 # host side of vf-pub0; not in the VM pool
helm upgrade virtfoundry virtfoundry/virtfoundry \
--version 0.5.0 \
-n virtfoundry-system \
-f values-kind.yaml \
-f values-kind-public.yaml \
--reuse-values
Attach the public network on the VM (UI → Public / deploy with public IP). From the laptop:
ping -c 2 10.0.50.10 # first address in the pool, if allocated
Your phone on Wi-Fi will not see 10.0.50.0/24 unless you add a route. That is expected: kind public is local to Docker, like a lab VLAN that only exists on this machine.
Do not enslave eth0
uplink: eth0 takes down kubelet inside the kind node. Recover with kind delete cluster --name virtfoundry and recreate.
Cleanup¶
kind delete cluster --name virtfoundry
docker network rm virtfoundry-pub # if you created it
Next¶
| Goal | Doc |
|---|---|
| First VM clicks | Quickstart |
| Helm keys | Configuration — public networking |
| VLAN vs house LAN on real nodes | Topologies |
| Why KubeVirt / Multus / CDI | Installation |