Create your own cluster

For a long time, I’ve been trying to achieve a better configuration in my home lab. Since I have been working with Kubernetes (k8s) for an extended period of time, I have always desired an overkill configuration with multiple nodes for high availability. However, looking at the costs related to running such a setup, I got depressed. I then explored alternatives and came to the conclusion… Raspberry Pis! I bought 6 Raspberry Pis and said which one should I use k0s, k3s or some other lightweight k8s? Then I said let’s go for k3s, it seems easier :D So the Raspberry Pis arrived but… I moved house then my Raspberries went missing in one of the boxes… Three months later, I stumbled upon them again amidst my collection of belongings – I tend to accumulate a lot of stuff – and by this point, I had changed jobs, moved again, and dealt with more complications… So after 2 years, here we are again… looking again at this project… so I will trust my old me saying the k3s is the best thing that I could use… So let’s look at the hardware that I have…

  • 6 Raspberries - 8 RAM each
  • 6 PoE hats for the Raspberries
  • 8 micro-SD cards of 128GB

The first issue that I had was that I used the default image and I didn’t customise it so… I had to remove the swap. To do that, I had to run the following commands:

sudo sync && sudo swapoff -a && sudo apt-get purge -y dphys-swapfile && sudo rm /var/swap && sudo sync

Then I forgot to update the Raspberry, so I had to run:

sudo apt autoremove &&  sudo apt update  &&  sudo apt upgrade 

Then I relised I needed to add the following text in the file: /boot/cmdline.txt

cgroup_enable=cpuset cgroup_enable=memory cgroup_memory=1 

After this change, the Raspberry needed to be restarted. Ah! Another thing that it required was to set up a static IP. Once that was done. I wanted to try Cillium and MetalLB, instead of flannel and Klipper load balancer that are the defaults from k3s.

# export MY_IP=$(ip a |grep global | awk '{print $2}' | cut -f1 -d '/')

# curl -sfL | INSTALL_K3S_EXEC="server" sh -s -  ' \
  --cluster-init   --node-ip=${MY_IP} --node-external-ip=${MY_IP} --bind-address=${MY_IP}  \
  --flannel-backend=none    --disable-network-policy   --cluster-cidr=   --service-cidr= \
  --disable "servicelb"   --disable "traefik"   --disable "metrics-server"

After keeping my fingers crossed, I had my first master node. I got scared because the pods
were in pending, but then I realised that I hadn’t installed the network policy. So it was fine :) I had to get the kubectl config in /etc/rancher/k3s/k3s.yaml to be able to connect to the cluster from my local.

One done 5 to go… To be able to add a new node the k8s token is required so… I went to the following path to get it:

# cat /var/lib/rancher/k3s/server/token

Once I had the token, I went to the next Raspberry. And I had to repeat the swap step and the cmdline step. Then I had to get the token, the current IP and the IP of the master node in my env vars. Once I had all those, I was able to run the following command:

# curl -sfL |  K3S_TOKEN=${MY_K3S_TOKEN} sh -s - server \
--server https://${MASTER_IP}:6443 --node-ip=${MY_IP} --node-external-ip=${MY_IP} --bind-address=${MY_IP}  \
--flannel-backend=none    --disable-network-policy   --cluster-cidr=   --service-cidr= \
--disable "servicelb"   --disable "traefik"   --disable "metrics-server"

Second Master node done… one more to go… I finished that and I started with the agents. Firstly - as you can guess… I did the swap step, the cmdline step and the static IP. As it happened with the master nodes, I needed the master node IP and the token. Once I had it I ran:

curl -sfL | INSTALL_K3S_EXEC="agent"  K3S_URL=https://${MASTER_IP}:6443 K3S_TOKEN=${MY_K3S_TOKEN}  sh -

After repeating that 3 more times… it was time to install Cilium… Since what I usually use for everything is helm… I used helm so I ran the following two commands:

helm repo add cilium
helm install cilium cilium/cilium --set global.containerRuntime.integration="containerd" \
--set global.containerRuntime.socketPath="/var/run/k3s/containerd/containerd.sock" \
--set global.kubeProxyReplacement="strict" --namespace kube-system

Then… I needed a coffee… with my lovely and warm coffee, it was time to install the load balancer. I just had to run the three following commands:

helm repo add metallb

helm install metallb metallb/metallb --namespace metallb-system  --create-namespace

cat << 'EOF' | kubectl apply -f -
kind: IPAddressPool
name: home-lab-pool
namespace: metallb-system
kind: L2Advertisement
name: home-lab
namespace: metallb-system
- home-lab-pool

and done.

If you followed my odyssey, you should have the same lab as I do if you want :D Good luck!

comments powered by Disqus