Mit ein paar günstigen RasPi-4-Mini-Computern und der leichtgewichtigen Kubernetes-Implementierung Microk8s von Canonical bauen Sie im Handumdrehen einen nützlichen Rechner-Cluster für zu Hause.
Ob ein einfacher Webserver für Security-Experimente, eine eigene Mediawiki-Instanz zum Aufzeichnen wertvoller Notizen oder eine lokale Gitlab-Installation zum Verwalten und automatisierten Übersetzen des Quellcodes: Eine private Mini-Rechen-Cloud, die für kleines Geld zu haben ist, wenig Strom verbraucht und somit dauerhaft im Betrieb sein kann, wäre für verschiedene Hobby-Projekte doch sehr praktisch. Erfreulicherweise gelingt ein solcher Aufbau mithilfe offener Hard- und Software in wenigen Stunden. Der vorliegende Artikel beschreibt eine auf RasPi-4-SBCs basierende Mini-Rechen-Cloud, auf der eine spezielle Kubernetes-Distribution für einen fast professionellen Betrieb verschiedener Applikationen sorgt.
Nachdem das Paket mit drei Raspberry-Pi-4-Minicomputern [1] (die Version mit 4 Gigabyte Arbeitsspeicher) endlich eingetroffen war, machte sich der Autor sofort daran, sie via Ethernet zu einem Cluster zu verbinden und Microk8s [2] von Canonical zu installieren. Dabei handelt es sich um eine leichtgewichtige, einfach zu installierende, weil nur aus einem Paket bestehende Kubernetes-Distribution aus dem Hause Canonical.
Da diese Distribution in Form eines Ubuntu-Snaps verfügbar ist, werden alle benötigten Binaries und die dazugehörigen Bibliotheken automatisch mitgeliefert, und alle Kubernetes-Dienste laufen auf Anhieb. Daher eignet sich diese Kubernetes-Version besonders gut für die Entwicklung von Prototypen, das Einrichten von Testinstallationen oder eben den Aufbau einer heimischen Mini-Rechen-Cloud für Hobbyprojekte. Trotz seiner geringen Größe ist Microk8s von der Cloud Native Computing Foundation [3] zertifiziert und somit bezüglich der Schnittstellen hundertprozentig kompatibel zum großen Bruder Kubernetes [4].
Die hier beschriebene Microk8s-Installation dauerte beim Autor insgesamt etwa zwei Stunden, wobei das eine oder andere nachgeschlagen werden musste. Mit ein wenig mehr Übung – und hoffentlich mithilfe dieses Artikels – kann man das sicherlich auch schneller bewerkstelligen. Die fertig eingerichtete Umgebung auf einem Raspberry-Pi-Cluster bietet dann eine tolle Spielwiese für das Experimentieren und den Betrieb Container-basierter Applikationen – und einen Hauch eines richtigen Rechenzentrums.
Die Hardware
Zusätzlich zu den Mini-Computern selbst benötigen Sie für jeden der RasPis noch drei Komponenten: ein Netzteil, eine MicroSD-Karte und ein Ethernet-Kabel.
Wenngleich es eine große Auswahl an kompatiblen Netzteilen gibt, hat der Autor sehr gute Erfahrungen mit den offiziell von der Raspberry Pi Foundation empfohlenen USB-C-Netzteilen [5] für den RasPi 4 gemacht und rät zu deren Verwendung.
Die MicroSD-Karte dient als nicht flüchtiger Speicher für das Betriebssystem Ubuntu, die Microk8s-Installation und die eigentlichen Applikationen. Für den hier beschriebenen Cluster kamen MicroSD-Karten von SanDisk mit 128 GByte Kapazität zum Einsatz.
Das Ethernet-Kabel stellt die Verbindung zwischen dem Raspberry Pi und dem Router oder Switch her und koppelt damit auch die einzelnen Rechner des Clusters. Aus Platzgründen können dabei flache Ethernet-Kabel vorteilhaft sein.
Ubuntu installieren
Im ersten Schritt müssen Sie auf den Mini-Rechnern ein Betriebssystem installieren. Für das hier beschriebene Setup diente aufgrund der umfangreichen Paket-Repositories und der Langzeitunterstützung (LTS) die Ubuntu Server Distribution von Canonical in der Version 18.04 als Basis. Inzwischen gibt es die Version 20.04 LTS von Ubuntu Server. Die hier beschriebenen Installationsanweisungen sind für beide Versionen gültig.
Das Ubuntu-Image für den Raspberry Pi beziehen Sie über die offizielle Ubuntu-Download-Seite [6]. Laden Sie von dort die 64-Bit-Version des Images herunter [7]. Die Prozessoren des Raspberry Pi basieren auf ARM-Kernen. Die neueste RasPi-4-Version setzt auf die BCM2711-CPU von Broadcom, die mit einer Taktfrequenz von 1,5 GHz läuft und einen 64-Bit-Quad-Core-Kern des Typs ARM Cortex-A72 unter der Haube hat. Da die ARM-Architektur einen eigenen Befehlssatz verwendet, würde ein Ubuntu-Image für x86-Prozessoren nicht funktionieren.
Nach Abschluss des Downloads entpacken Sie die Archivdatei mit dem Image von Ubuntu Server 20.04 zuerst mit einem der üblichen Programme, etwa mit Tar, und kopieren es anschließend auf die MicroSD-Karte. Die Download-Webseite von Canonical enthält dazu Anleitungen für Linux, MacOS und Windows.
Der Autor dieses Artikels ist üblicherweise zu faul, für die initiale Konfiguration einen Bildschirm und eine Tastatur an den Raspberry Pi anzuschließen. Stattdessen nutzt er die Möglichkeit, sich nach dem ersten Boot-Vorgang per SSH mit dem Mini-Rechner zu verbinden. Um den SSH-Dienst standardmäßig – also bereits beim allerersten Start – zu aktivieren, müssen Sie nach dem Beschreiben der MicroSD-Karte in deren Root-Verzeichnis eine Datei namens »ssh« anlegen, die auch leer sein darf. Das Vorhandensein der Datei aktiviert den SSH-Daemon beim ersten Boot-Vorgang, sodass Sie sich von vornherein über SSH mit dem Raspberry Pi verbinden können.
Damit es nun losgehen kann, bestücken Sie die Mini-Rechner noch mit den MicroSD-Karten, verbinden sie über Ethernet mit einem Router oder Switch und versorgen sie mit Strom. Um sich mit einem der RasPis zu verbinden, müssen Sie zuerst dessen IP-Adresse ermitteln. Dazu loggen Sie sich auf dem Router ein und sehen in der Liste der angeschlossenen Geräte nach. Haben Sie während des Beschreibens der MicroSD-Karten keine weiteren Einstellungen verändert (außer dem Aktivieren des SSH-Daemons), erscheinen die RasPis unter dem Namen ubuntu.
Mit diesen Informationen melden Sie sich mit dem Befehl »ssh ubuntu@RasPi-IP« von einem anderen Rechner im Netz aus auf einem der Mini-Computer an. Sofern Sie in der initialen Konfiguration der Raspberry Pi nichts verändert haben, geben Sie als Passwort »ubuntu« ein. Beim ersten Einloggen fragt das System nach einem neuen Passwort. Nach dessen Eingabe melden Sie sich fortan als Nutzer ubuntu mit dem neuen Passwort an.
Microk8s installieren
Um Microk8s installieren und verwenden zu können, benötigen Sie Cgroups. Die Bezeichnung steht für Control Groups, ein Linux-Kernel-Feature, das die Begrenzung verschiedener Ressourcen wie CPU, RAM, Disk I/O, Netzwerk und so weiter kontrolliert. Ursprünglich wurde das Cgroups-Feature von Google-Angestellten, allen voran Paul Menage und Rohit Seth, unter dem Namen Process Containers entwickelt. Gegen Ende 2007 hat sich der Name in Control Groups geändert, um die Mehrdeutigkeit des Container-Begriffs zu umgehen.
Da das Cgroups-Feature standardmäßig nicht aktiviert ist, müssen Sie es auf dem Ubuntu Server Image zunächst einmal in Betrieb nehmen. Dazu melden Sie sich via SSH auf dem Raspberry Pi an und passen die Boot-Parameter in der Datei »nobtcmd.txt« (früher: »cmdline.txt«) an. Sie starten einen Editor Ihrer Wahl mit Sudo-Rechten und fügen die Zeile »cgroup_enable=memory cgroup_memory=1« in die Datei ein. Nach dem Speichern müssen Sie den Raspberry Pi neu starten, damit die Änderung greift. Da Sie ohnehin schon auf dem Raspberry Pi eingeloggt sind, klappt das am einfachsten mit dem Befehl »sudo reboot«.
Nach dem anschließenden Neustart installieren Sie die Microk8s-Distribution ganz einfach als Ubuntu-Snap [8]. Der Snap-Mechanismus von Canonical verfügt über ein Konzept namens Channel. Ein solcher Channel definiert, welches Release eines Snaps installiert und anschließend auf Updates überprüft wird. Der Microk8s-Snap folgt den Versionen des Upstream-Kubernetes, bei dem ein neues Release etwa alle drei Monate erscheint. Als dieser Artikel geschrieben wurde, war 1.19.3 die neueste Kubernetes-Version, sodass der entsprechende Microk8s-Snap sich mit dem Befehl aus der ersten Zeile von Listing 1 installieren ließ.
Nach Abschluss der Microk8s-Installation sorgen Sie für mehr Komfort bei der Bedienung auf der Kommandozeile [9]. Dazu fügen Sie das Benutzerkonto der Microk8s-Gruppe hinzu und passen den Eigentümer des Verzeichnisses »~/.kube/« an (Listing 1, Zeile 2 und 3) und starten anschließend Microk8s (Zeile 4 und 5). Ist die Installation ordnungsgemäß verlaufen, zeigt der Aufruf »microk8s kubectl get nodes« die aktuell verfügbaren Rechenknoten an – in diesem Fall genau einen Raspberry Pi, da wir noch keine weiteren Rechenknoten hinzugefügt haben (Zeile 19). Das Kommando »microk8s kubectl get services« gibt den Standard-Service »kubernetes« aus, da wir aktuell noch keine eigenen Kubernetes-Services angelegt haben (Zeile 22).
Listing 1
Initiales Benutzer-Setup
$ sudo snap installMicrok8s --classic --channel=1.18/stable $ sudo usermod -a -Gmicrok8s $USER $ sudo chown -f -R $USER ~/.kube $ su - $USER $ microk8s status --wait-ready microk8s is running addons: dashboard: disabled dns: disabled helm: disabled helm3: disabled ingress: disabled kubeflow: disabled metallb: disabled metrics-server: disabled rbac: disabled registry: disabled storage: disabled $ microk8s kubectl get nodes NAME STATUS ROLES AGE VERSION ubuntu Ready <none> 10m v1.18.0 $ microk8s kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 10m
Sieht die Ausgabe also wie in Listing 1 aus, kann man zu einer erfolgreichen Microk8s-Installation gratulieren. Möchten Sie einen Raspberry-Pi-Cluster aus mehreren Mini-Rechnern aufbauen, müssen Sie die gezeigten Schritte für jeden davon wiederholen.
Nginx-Deployment
Jetzt gilt es, sich die Vorzüge einer Kubernetes-Umgebung für das Deployment der eigentlichen Applikationen zunutze zu machen [10]. Wie das geht, soll am Beispiel des populären HTTP- und Reverse-Proxy-Servers Nginx [11] demonstriert werden. Zunächst legen Sie, wie in Listing 2 gezeigt, ein neues Kubernetes-Deployment an (Zeile 1). Es trägt den Namen »my-nginx« und verwendet das Nginx-Docker-Image.
Listing 2
Neues Kubernetes-Deployment
$ microk8s.kubectl create deployment my-nginx --image nginx deployment.apps/my-nginx created $ microk8s.kubectl get all NAME READY STATUS RESTARTS AGE pod/my-nginx-9b596c8c4-ngd2q 1/1 Running 0 12m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/my-nginx 1/1 1 1 12m NAME DESIRED CURRENT READY AGE replicaset.apps/my-nginx-9b596c8c4 1 1 1 12m $ microk8s.kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h
Mit dem Unterbefehl »get all« (Zeile 4) lässt sich verifizieren, dass das Deployment tatsächlich erfolgreich angelegt wurde: Kubernetes zeigt nun ein Deployment namens »deployment.apps/my-nginx« sowie den dazugehörigen Pod »pod/my-nginx-9b596c8c4-ngd2q« an. Als Pod bezeichnet man die kleinste Einheit, die Kubernetes anlegen und verwalten kann. Technisch gesehen handelt es sich dabei um eine Gruppe aus einem oder mehreren Containern, die über gemeinsame Speicher- und Netzwerkressourcen verfügen sowie eine gemeinsame Spezifikation haben, die bestimmt, wie die Container ausgeführt werden sollen.
Wo aber kommt dieser Begriff her? Nun, im Kubernetes-Ökosystem werden häufig Docker-Container verwendet. Das Symbol und Maskottchen von Docker ist bekanntlich ein Wal. Die meisten Wale sind sehr gesellig, weisen ein hochentwickeltes Sozialverhalten auf und leben in Gruppen von meist 10 bis 50 Tieren. Im Deutschen bezeichnet man solche Walgruppen als Schulen, im Englischen als Pods. Somit ist also ein Kubernetes-Pod eine Anspielung auf eine Gruppe von Docker-Containern.
Mit Kubernetes lässt sich die Verfügbarkeit der Applikation quasi im Handumdrehen verbessern. Dazu erhöht man mit dem Parameter »–replicas« die Anzahl der Replicas in einem Kubernetes-Deployment. Listing 3 zeigt, wie das für das »my-nginx«-Deployment klappt (Zeile 1). Der anschließende Aufruf des Unterbefehls »get all« zeigt nun drei gerade laufende Pods (Zeile 4).
Listing 3
Anzahl der Replicas erhöhen
$ microk8s.kubectl scale deployment my-nginx --replicas 3 deployment.apps/my-nginx scaled $ microk8s.kubectl get all NAME READY STATUS RESTARTS AGE pod/my-nginx-9b596c8c4-4jp7d 1/1 Running 0 7s pod/my-nginx-9b596c8c4-7ql2q 1/1 Running 0 7s pod/my-nginx-9b596c8c4-ngd2q 1/1 Running 0 14m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/my-nginx 3/3 3 3 14m NAME DESIRED CURRENT READY AGE replicaset.apps/my-nginx-9b596c8c4 3 3 3 14m
Kubernetes-Replicas legen fest, wie viele Pods parallel laufen sollen. Damit lässt sich einerseits die eigentliche Anwendung für den Fall skalieren, dass mehr Anfragen bedient werden müssen. Andererseits erhöhen Replicas die Verlässlichkeit, da der Absturz eines einzelnen Pods nicht gleich die ganze Anwendung gefährdet. Natürlich sind Replicas erst dann richtig sinnvoll, wenn die einzelnen Pods auf unterschiedlichen physikalischen Rechenknoten laufen – also nachdem Sie dem Microk9s-Cluster mehrere RasPis hinzugefügt haben.
Damit sich das Nginx-Deployment auch von außen errreichen lässt, also nicht nur innerhalb des Raspberry Pi, müssen Sie noch einen sogenannten NodePort hinzufügen (Listing 4). Nun können Sie die Nginx-Anwendung auch aus dem heimischen WLAN erreichen. Um das zu testen, setzen Sie von jedem Host im eigenen Funknetzwerk einfach den Befehl »curl 127.0.0.1:30178« ab. Dies sollte eine Ausgabe ähnlich der aus Listing 5 erzeugen. In diesem Fall haben Sie nun eine funktionierende Microk8s-Installation am Start und können jede Menge spannende Experimente machen.
Listing 4
Exponieren eines Kubernetes-Diensts
$ microk8s.kubectl expose deployment my-nginx --port 80 --name my-nginx-np --type NodePort service/my-nginx-np exposed $ microk8s.kubectl get services NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h my-nginx-np NodePort 10.152.183.73 <none> 80:30178/TCP 13s $ microk8s.kubectl get all NAME READY STATUS RESTARTS AGE pod/my-nginx-9b596c8c4-4jp7d 1/1 Running 0 3m34s pod/my-nginx-9b596c8c4-7ql2q 1/1 Running 0 3m34s pod/my-nginx-9b596c8c4-ngd2q 1/1 Running 0 17m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/kubernetes ClusterIP 10.152.183.1 <none> 443/TCP 47h service/my-nginx-np NodePort 10.152.183.73 <none> 80:30178/TCP 20s NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/my-nginx 3/3 3 3 17m NAME DESIRED CURRENT READY AGE replicaset.apps/my-nginx-9b596c8c4 3 3 3 17m
Listing 5
Nginx-Deployment validieren
$ curl RasPiIP:30178
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Fazit
Kubernetes ist zwar recht recht komplex, aber das Ubuntu-Snap Microk8s lässt sich verhältnismäßig einfach installieren und erlaubt spannende Experimente mit einem Mini-Cluster, der im Prinzip bereits so funktioniert wie in einem Rechenzentrum. Ein solches Projekt kann über den Lerneffekt hinaus auch tatsächlich nützliche Applikationen skalierbar und hochverfügbar machen. Dank des Raspberry Pi hält sich dabei der finanzielle Aufwand noch in Grenzen. (jcb/jlu)
Infos
- Raspberry Pi 4: https://www.raspberrypi.org/products/raspberry-pi-4-model-b/
- Microk8s: https://microk8s.io
- Clound Native Computing Foundation: https://www.cncf.io
- Kubernetes: https://kubernetes.io
- USB-C-Netzteil: https://www.raspberrypi.org/products/type-c-power-supply/
- Ubuntu für Raspberry Pi: https://ubuntu.com/download/raspberry-pi
- Ubuntu-Image für ARM64: https://ubuntu.com/download/raspberry-pi/thank-you?version=20.04.4&architecture=server-arm64+raspi
- Microk8s installieren: https://ubuntu.com/tutorials/install-a-local-kubernetes-with-microk8s#2-deploying-microk8s
- Microk8s-Dokumentation: https://microk8s.io/docs/
- Microk8s lokal nutzen: https://kubernetes.io/blog/2019/11/26/running-kubernetes-locally-on-linux-with-microk8s/
- Nginx: https://nginx.org







Danke für den einführenden Artikel. Was mich bei diesem Setup allerdings brennend interessiert: Welche Erfahrungen hat der Autor mit dem Storage auf seinen Raspis? Was verwendet er? nfs, longhorn, Ceph? Was ist hier sinnvoll? Welche Erfahrungen gibt es?