En esta ocasión vamos a “bajarnos” por un momento de la nube, y vamos a explicar como montar un cluster de Kubernetes on-premise sobre una Raspberry Pi 4.
Hardware a utilizar
El material que vamos a utilizar es el siguiente:
- 1 x RaspBerry Pi 4 de 8GB de RAM
- 1 x RaspBerry Pi Zero 2W (En esta ocasión utilizaremos solo 1 RaspBerry Pi Zero 2W que corresponderá a un solo nodo, aunque podremos llegar a tener has 4 nodos)
- 2 x MicroSD una de 64GB y otra de 128GB
- 1 x Alimentador de corriente USB-C
- 1 x Placa ClusterHat 8086 v.2.5 que incluye conector USB a Raspberry Pi 4
- 1 x Carcasa transparente sobredimensionada especial para albergar ClusterHat
- 1 x Adaptador Micro HDMI a HDMI
- 1 x Cable Ethernet
- Disipadores para Raspberry Pi 4 y un ventilador de 30mmx30mm de 5V
- 1 x Lector de tarjetas MicroSD para instalar las imágenes de sistema operativo

Preparar las imágenes de las Raspberrys
Lo primero que haremos será preparar el software que tendrá instalado cada Raspberry. En nuestro caso la Raspberry Pi 4 de 8GB será el master del cluster y cada Raspberry Pi zero 2w (en mi caso solo una de momento) corresponderá a cada nodo del cluster.
Las imágenes se pueden descargar de la web del proyecto clusterctrl de Cluster HUT de este enlace.
Bajaremos la imagen CNAT – Desktop Controller (STD) para la RaspBerry Pi 4 y para cada Zero 2W una imagen Px de 64 bits, porque no queremos que cada raspberry Pi zero sea un nodo de la red, de no ser así tendremos que bajar versión CBRIDGE.
Para quemar las imágenes en las microSDs usamos Balena:


Con esto ya tendríamos preparado todo a nivel de software.
Montaje de ClusterHat (RaspBerry Pi Zero 2W y RaspBerry Pi 4 en carcasa
Veremos el montaje de cada uno de los componentes a nivel de hardware que realmente es sencilla.
Primero montamos los 4 disipadores de calor a las Raspberry 4:


Luego quitamos los plásticos protectores de la carcasa y encajamos la Raspberry Pi 4 en la base:


Encajamos la Raspberry PI 4 sobre los 4 tornillos de la carcasa y añadimos un segundo grupo de tornillos:


Luego colocamos con cuidado la placa ClusterHAT 8086 sobre los pines de las Raspberry 4 y sobre los tornillos:


Colocamos el siguiente grupo de tornillos con el soporte lateral delantero:

Por último montamos el resto de soportes junto con la Raspberry Pi Zero 2W y conectamos el USB desde la Raspberry Pi 4 a miniUSB de la placa ClusterHAT:




Configuración de ClusterHAT
Lo siguiente que haremos será configurar nuestra placa clusterHAT, para ello utilizaremos el comando clusterctrl / clusterhat que viene incluido en la imagen de la Raspberry PI 4.
Por defecto la placa de clusterHAT está apagada. Estos son algunos de los comandos básicos:
$ clusterctrl on # Turn power to all Pi Zero on
$ clusterctrl off # Turn power to all Pi Zero off
$ clusterctrl on p1 # Turn power on to Pi Zero in slot P1
$ clusterctrl on p1 p3 p4 # Turn power to Pi Zeros in slot P1, P3 and P4 on
$ clusterctrl off p2 p3 # Turn power off to Pi Zeros in slots P2 and P3
$ clusterctrl alert on # Turns on ALERT LED
$ clusterctrl alert off # Turns off ALERT LED
$ clusterctrl hub on # Turns on USB hub (default)
$ clusterctrl hub off # Turns off USB hub
$ clusterctrl led on # Enables Power & P1-P4 LED on Cluster HAT (default)
$ clusterctrl led off # Disables Power & P1-P4 LED on Cluster HAT (does not disable ALERT LED)
$ clusterctrl wp on # Write protects HAT EEPROM
$ clusterctrl wp off # Disables EEPROM write protect (only needed for updates)
En nuestro caso lanzaremos estos comandos en este orden:
$ clusterctrl on p1
$ clusterctrl alert on
$ clusterctrl hub on
$ clusterctrl led on
$ clusterctrl wp on
Configuración del SSH en las raspberrys
Luego habilitamos el servicio de SSH en la Raspberry Pi 4 para poder acceder remotamente.
$ sudo su -
$ raspi-config
Interface Options -> SSH
con esto ya tendremos el servicio habilitado, podemos comprobarlo con:
$ systemctl status ssh
Tambien modificaremos el hostname de la raspi 4 desde raspi-config -> System Options -> Hostname, cambiamos “cnat” por “masterpi”
Ahora apagamos el cluster. Y extraemos la tarjeta microSD de la Raspberry Pi Zero 2W. Luego la insertamos en el adaptador de tarjetas SD y la abrimos con el PC.
Una vez dentro creamos un fichero llamado “SSH” dentro de la partición boot de la microSD de las raspi Zero.

Ademas del archivo SSH hay que crear otro llamado userconf.txt que tendrá el usuario y la contraseña encriptada de los datos de conexión por ssh. Para generarlo podemos lanzar esta comando (en mi caso posicionado dentro de la carpeta /Volumes/boot que es donde me monta la microSD de la raspi zero):
$ echo "pi:"$(echo 'clusterctrl' | openssl passwd -stdin) > userconf.txt
Con esto ya podemos acceder por SSH desde la raspi 4 a las raspberrys Zeros por SSH utilizando el usuario pi y la clave clusterctrl, obviamente la cambiaremos la primera vez que accedamos por seguridad.
Configuramos el archivo /etc/hosts de la raspi 4:
127.0.0.1 localhost
127.0.1.1 masterpi
172.19.181.254 masterpi masterpi.local
172.19.181.4 p4 p4.local
172.19.181.3 p3 p3.local
172.19.181.2 p2 p2.local
172.19.181.1 p1 p1.local
En nuestro caso como solo tenemos un nodo con una raspi Zero conectado al P4 por eso la placa de clusterHut le asigna la primera IP 172.19.181.1.
Lo siguiente será generar una llave SSH en la raspi4 y copiar la llave publica en el archivo .ssh/authorized_keys de cada raspi Zero.
root@masterpi:~# ssh-keygen -t rsa -b 4096 -C "pi@masterpi.local"
root@masteroi:~# cat ~/.ssh/id_rsa.pub
Luego creamos el archivo /root/.ssh/config en al raspi 4 con el siguiente contenido:
Host p1
Hostname 172.19.181.4
User pi
Host p2
Hostname 172.19.181.3
User pi
Host p3
Hostname 172.19.181.2
User pi
Host p4
Hostname 172.19.181.1
User pi
Copiamos la clave en los nodos con los siguientes comandos desde la raspi4:
$ cat ~/.ssh/id_rsa.pub | ssh pi@p1.local "mkdir .ssh;cat >> .ssh/authorized_keys"
La clave de usuario de las raspberrys pi zero es la que indicamos anteriormente en el archivo userconfig.txt.
Probamos que ya podemos acceder al nodo por ssh:
$ ssh p1
y aprovechamos y actualizamos el nodo:
$ sudo su -
$ apt-get update
$ apt-get upgrade
Optimizando Raspberrys para Kubernetes
Instalamos el paquete ntpdate en todos los nodos ya que la hora de la Raspberry y de las Raspi Zero no coinciden:
$ apt-get install ntpdate
Vamos a crear un archivo config.txt en la partición /boot de la raspberry 4 y la raspberry pi Zero con la siguiente configuración, para que dediquen la memoria a procesador y no a la parte gráfica (en /boot/config.txt):
# Debajo de [all]
gpu_mem=16
Una particularidad de Kubernetes es que es muy sensible a las latencias, así que vamos a comprobar como se comporta nuestra raspberry pi 4 en este punto con el siguiente comando:
$ fio --loops=5 --size=500m --filename=fiotest.tmp --stonewall --ioengine=libaio --direct=1 --name=Seqwrite --bs=1m --rw=write

También necesitamos tener configurado ciertos requisitos del firewall de iptables, tanto en la raspberry pi4 como en las pi zero:
$ sudo iptables -F
$ sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
$ sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
$ sudo reboot
Por último, hay que configurar Raspbian para que admita cgroups. Para ello, modificamos el fichero /boot/cmdline.txt en la partición boot de cada raspberry añadiendo cgroup_memory=1 cgroup_enable=memory:
console=serial0,115200 console=tty1 root=PARTUUID=34565118-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait cgroup_memory=1 cgroup_enable=memory
y con esto ya tendríamos todo lo necesario para instalar Kubernetes en nuestro cluster.
Instalación de Kubernetes
Para instalar kubernetes utilizaremos el proyecto k3s.
Instalamos k3s en la raspberry pi 4 con el siguiente comando:
root@masterpi:~# curl -sfL https://get.k3s.io | sh -
si todo va bien:
root@masterpi:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
masterpi Ready control-plane,master 61s v1.25.3+k3s1
Para cada uno de los nodos worker (raspberry pi zero 2w) hay que copia del archivo /var/lib/rancher/k3s/server/node-token el token que se ha generado en la raspbery pi 4, y lanzamos el siguiente comando en cada nodo worker (sustituimos <MYTOKEN>):
root@p1:~# curl -sfL https://get.k3s.io | \
K3S_URL=https://masterpi.local:6443 \
K3S_TOKEN=<MYTOKEN> \
sh -
y si todo va bien:
root@p1:~# kubectl get nodes
NAME STATUS ROLES AGE VERSION
p1 Ready <none> 23s v1.25.3+k3s1
masterpi Ready control-plane,master 3m37s v1.25.3+k3s1
Ahora “tageamos” el nodo p1 como worker en el cluster:
$ kubectl label node p1 kubernetes.io/role=worker