Skip to content

Build Kubernetes Cluster from Scratch

Use this guide to rebuild a homelab cluster from bare metal or new VM images using this repo as the source of truth.

Follow Prerequisites to install tooling and update the Ansible inventory.

Run the provisioning playbook from the repo root:

Terminal window
ansible-playbook -i ansible/inventory/hosts.yaml \
ansible/playbooks/provision-cpu.yaml \
-e @ansible/group_vars/all.yaml

If you need GPU support, use the GPU playbooks in ansible/playbooks/.

Run on the control plane node. Pick a pod CIDR that does not overlap your LAN or service CIDR. If you prefer to skip pinning a pod CIDR, omit --pod-network-cidr and keep the Cilium defaults.

Terminal window
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
kubectl taint nodes --all node-role.kubernetes.io/control-plane-

If you want OIDC for Headlamp, follow the optional OIDC section in Kubernetes before the first kubeadm init.

Update the control plane IP in infrastructure/cilium/values.cilium, then install Cilium:

Terminal window
CILIUM_VERSION=$(grep -E "cilium_version:" ansible/group_vars/all.yaml | head -n 1 | awk -F'"' '{print $2}')
cilium install --version $CILIUM_VERSION --values infrastructure/cilium/values.cilium

Step 5: Install ArgoCD and bootstrap GitOps

Section titled “Step 5: Install ArgoCD and bootstrap GitOps”
Terminal window
kubectl apply -k bootstrap/argocd
kubectl wait --for=condition=available --timeout=600s deployment/argocd-server -n argocd
kubectl apply -f bootstrap/root.yaml

Step 6: Configure Vault and External Secrets

Section titled “Step 6: Configure Vault and External Secrets”

Follow Vault to initialize Vault and create the required secrets for ExternalDNS, cert-manager, and the Tailscale operator.

Terminal window
kubectl get nodes
kubectl get pods -A
kubectl get apps -n argocd

Use this for a local dry run before touching hardware. To keep resources low, set a single-node cluster and smaller VM sizing. If resources are tight, disable Hubble UI and Relay for the rehearsal:

Terminal window
WORKER_COUNT=0 VM_CPUS=2 VM_MEMORY=3G VM_DISK=12G CILIUM_HUBBLE_ENABLED=false ./scripts/local-cluster.sh up

Destroy the rehearsal cluster when done:

Terminal window
./scripts/local-cluster.sh down