Configuring Kubernetes on Raspberry Pi 5 – (Single Node Cluster)

sudo apt update && sudo apt upgrade -y
sudo apt install -y iptables iptables-persistent curl iproute2 dphys-swapfile
grep -q '^CONF_SWAPSIZE=' /etc/dphys-swapfile && \
sudo sed -i 's/^CONF_SWAPSIZE=.*/CONF_SWAPSIZE=2048/' /etc/dphys-swapfile || \
echo 'CONF_SWAPSIZE=2048' | sudo tee -a /etc/dphys-swapfile
sudo systemctl restart dphys-swapfile
sudo vi /boot/cmdline.txt
sudo vi /boot/firmware/cmdline.txt
cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory
free -h
sudo reboot
sudo vi k3s-setup.sh
#!/bin/bash
set -e

echo "Detecting IP address..."
NODE_IP=$(ip -4 addr show eth0 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}') || true
if [ -z "$NODE_IP" ]; then
    NODE_IP=$(ip -4 addr show wlan0 2>/dev/null | grep -oP '(?<=inet\s)\d+(\.\d+){3}')
fi
if [ -z "$NODE_IP" ]; then
    echo "Unable to detect IP address on eth0 or wlan0. Exiting."
    exit 1
fi
echo "Detected node IP: $NODE_IP"

echo "Installing K3s with proper kubeconfig permissions..."
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server \
  --disable=traefik \
  --flannel-backend=host-gw \
  --tls-san=$NODE_IP \
  --bind-address=$NODE_IP \
  --advertise-address=$NODE_IP \
  --node-ip=$NODE_IP \
  --cluster-init \
  --write-kubeconfig-mode=644" sh -

echo "Setting up kubectl access for current user..."
mkdir -p ~/.kube
sudo cp /etc/rancher/k3s/k3s.yaml ~/.kube/config
sudo chown $(id -u):$(id -g) ~/.kube/config
sudo chmod 600 ~/.kube/config

sudo systemctl daemon-reload
echo "K3s installed successfully!"
echo "Restarting K3s service... (Wait 30 seconds)"
sudo systemctl restart k3s
sleep 10
echo "Checking cluster nodes Status..."
sleep 20


kubectl get nodes
echo "K3s Cluster Ready!!!"
sudo chmod +x k3s-setup.sh
sudo ./k3s-setup.sh
kubectl get nodes
kubectl get pods -A
NAME          STATUS   ROLES                       AGE     VERSION
raspberrypi   Ready    control-plane,etcd,master   2m   v1.33.5+k3s1
sudo reboot
kubectl get nodes
sudo vi /usr/local/bin/k3s-dynamic-start.sh
#!/bin/bash
HOSTNAME="raspberrypi.local"  # or your dynamic DNS
IP=$(hostname -I | awk '{print $1}')

exec /usr/local/bin/k3s \
  server \
  --disable=traefik \
  --flannel-backend=host-gw \
  --tls-san=$HOSTNAME \
  --bind-address=$IP \
  --advertise-address=$IP \
  --node-ip=$IP \
  --cluster-init \
  --write-kubeconfig-mode=644
sudo chmod +x /usr/local/bin/k3s-dynamic-start.sh

edit k3s.service file

/etc/systemd/system/k3s.service

add following in k3s.service

ExecStart=/usr/local/bin/k3s-dynamic-start.sh
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl restart k3s

configure k3s service file if required at /etc/systemd/system/k3s.service

[Unit]
Description=Lightweight Kubernetes
Documentation=https://k3s.io
Wants=network-online.target
After=network-online.target

[Install]
WantedBy=multi-user.target

[Service]
Type=exec
EnvironmentFile=-/etc/default/%N
EnvironmentFile=-/etc/sysconfig/%N
EnvironmentFile=-/etc/systemd/system/k3s.service.env
KillMode=process
Delegate=yes
User=root
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNOFILE=1048576
LimitNPROC=infinity
LimitCORE=infinity
TasksMax=infinity
TimeoutStartSec=0
Restart=always
RestartSec=5s
ExecStartPre=-/sbin/modprobe br_netfilter
ExecStartPre=-/sbin/modprobe overlay
ExecStart=/usr/local/bin/k3s-dynamic-start.sh