Giovanni's Diary > Chronological > Ephemeris > Entries >

2025-05-19 - Setting up a local cluster

Hi,

today I spent most of my day setting up a local cluster for kubernetes. I thought this would be nice and simple but It wasn't, let me tell you why.

The reason why I wanted to have my own custom cluster is mostly because I don't like popular solutions based on virtual machines. I have always done all my development in a cluster with Kind and that has been awesome, Kind is light weight and easy to setup. However, Kind uses docker containers and It works only locally. For my application, I need to test It on various cluster topologies, especially in multiple nodes running different kernels. I have this requirement because my application behaves differently based on the number of running kernels in the cluster since I need to load eBPF programs in the kernel.

Well, I tried to use Minikube but both my laptop and my Desktop would completely freeze. Minikube is incredibly resource hungry and a lot of the drivers do not work at all. Additionally, I have so many problems on running particular topologies with multiple nodes and different images. I think Minikube is slow and heavy, and buggy. The alternatives do not satisfy me for similar reasons: I knew that I could setup a simple and light cluster on my own and have any kind of configuration I wanted, like 2 nodes on my desktop, one on my laptop and another one on my other laptop for example. So I started setting up everything by myself.

My vision is to have any number of Linux images running via qemu and KVM, all connected to the same network. The images would then run the various kubernetes daemons and I would control everything from a tmuxed terminal. All of this is managed centrally using a bunch of scripts. Since I am bootstrapping everything, I have full control on any part of my cluster, making It simple to hack. However, I have to say that setting up this did not went exactly smoothly.

To make the machines communicate with the internet and themselves I needed to setup some tap interface and connect them via a bridge. You need to do this correctly in order to make everything work, my final script to bootstrap the interface is the following:

#!/bin/bash
set -e

echo "Creating bridge br0..."

sudo ip link set br0 down 2>/dev/null || true
sudo ip link delete br0 type bridge 2>/dev/null || true

sudo ip link add name br0 type bridge
sudo ip addr add 192.168.50.1/24 dev br0
sudo ip link set br0 up

echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
sudo iptables -t nat -A POSTROUTING -s 192.168.50.0/24 ! -o br0 -j MASQUERADE

for i in 0 1; do
  tap="tap$i"

  echo "Setting up $tap..."

  sudo ip link set "$tap" down 2>/dev/null || true
  sudo ip tuntap del "$tap" mode tap 2>/dev/null || true

  sudo ip tuntap add dev "$tap" mode tap
  sudo ip link set "$tap" up
  sudo ip link set "$tap" master br0
done

echo "Bridge and tap devices ready."

I also made a script to clean everything and can be found on the project's repo. Then I needed to setup a static IP in each machine and … It didn't quite work. The problem was that I also needed to set a different MAC address for each virtual machine or the TCP/IP stack could not route the packets… that took a LOONG time to figure out because nothing hinted that this was the problem. I basically tried random things for 3 hours until this worked, wonderful.

Thankfully I endured that and now I am here to tell a beautiful story instead of being ashamed of my own incompetence. Anyway, now I have a bunch of VMs all connected to the same network that can ping each other and the internet. Next time I will make so that they will automatically install k3s (a kubernetes distribution) and we should be good to go.

Another interesting thing I learned is cloud-init which helps setting up the userspace of the VMs from an external config file, which looks like this:

#cloud-config
users:
    - name: fedora
      groups: user,wheel
      hashed_passwd: ...
      lock_passwd: false
      sudo: ALL=(ALL) NOPASSWD:ALL
write_files:
  # Enable password authentication in ssh
  - path: /etc/ssh/sshd_config.d/20-enable-passwords.conf
    content: |
      PasswordAuthentication yes
runcmd:
  - systemctl restart NetworkManager
  - systemctl restart sshd
  - nmcli connection up static-ens3

I find this very useful, thank you Fedora for letting me discover this.

The rest of my day was spent signing an enormous amount of documents for my internship and doing physics exercises at the blackboards in my university until closing hour, had a lasagna and now back to study physics.

– Giovanni


Travel: Ephemeris, Index