Kubernetes ist ja derzeit in aller Munde. So konnte ich mich, vor allem mit meiner frisch entdeckten Liebe zu Docker, nicht davon fernhalten auch mal einen Cluster aufzusetzen. Als Ausgangslage hierfür kamen folgende Komponenten zum Einsatz:

  • Rasberry Pi 3+
  • Rasberry Pi 4 2GB Ram
  • Pine64 1GB
  • Samsung Evo 128GB SD x1
  • Sandisk 32GB SD x2
  • Ethernet Hub USB powered

Voraussetzungen

Als Software bzw. OS kam für die Rasberry Pis das HypriotOS der Piraten und für den Pine64 das Xenial Minimal Image zum Einsatz. Ich habe mich für HypriotOS entschieden, da es 1) stets aktuell gehalten wird und 2) dort bereits Docker vorinstalliert ist. So entfällt ein notwendiger Installationsschritt.

Geflashed wurden die SD-Karten mit balenaEtcher, da dieses ein effizientes und schnelles Tool für die Installation der Images ist. Und da der Einsatz von Kubernetes noch anstrengend genug wurde, war das genau der richtige Schritt. Vorab muss noch erwähnt werden, dass die Hostnamen noch per Hand angepasst werden müssen. Das habe ich in den ersten paar Versuchen nämlich nicht getan, was im folgenden Konfigurationsverlauf zu massiven Schwierigkeiten geführt hat. Am besten verwendet man einfach den command hostnamectl zum Anpassen des Hostnames. Dabei muss im Nachgang noch die /etc/hostnames sowie /etc/hosts angepasst und unter /etc/cloud/cloud.cfg noch der Flag preserve_hostname auf true geändert werden.

Bei dem Pine64 ist der Flashvorgang identisch. Nur muss hier das andere Basisimage ausgewählt werden. Da hier kein Docker vorinstalliert ist, erfolgte die Installation separat (Installationsvorgang, siehe: Get Docker Engine).

Sollte im heimischen Netz kein DHCP-Server im Betrieb sein, sollten die RasberryPis/Pine64 noch statische IP-Adressen bekommen. Der Schritt war bei mir, dank DHCP-Server, nicht notwendig. Ist DHCP aktiviert, müssen für den nächsten Schritt die IP-Adressen ermittelt werden, damit wir auf die Geräte per SSH zugreifen können.

And so... it beginns...

Grundsätzlich habe ich mich an das Tutorial "Kubernetes Cluster auf Raspberry PIs" gehalten. Allerdings war es mir per Ansible nicht möglich automatisiert Kubernetes auf den Pine64 zu installieren. Deshalb habe ich die Rasberrys automatisiert und den Pine64 manuell mit Kubernetes bespielt.

Das Ergebnis sah erst mal vielversprechend aus:

[email protected]:~# kubectl get nodes
NAME          STATUS   ROLES    AGE   VERSION
pi3-node      Ready    worker   21h   v1.13.2
pi4-master    Ready    master   21h   v1.13.2
pine64        Ready    worker   20h   v1.13.2

Anmerkung: Ursprünglich wollte ich, wegen der besseren Performance, den Pi3 zum Master machen. Allerdings hat dieses dank mangelnder Leistung bei mir irgendwie nicht funktioniert. Zum Abschluss der "kubeadm init"-Phase gab es ein 4Minuten-Timeout, was leider jedes Mal erreicht wurde. Deshalb musste ich zwangsweise den Pi4 zum master machen, was problemlos funktioniert hat.

In meiner unendlichen Euphorie bin ich davon ausgegangen, ich könne nun direkt Pods (=Docker Container) im Cluster ausführen lassen. Allerdings gab es noch einige Fallstricke zu entwirren bevor der erste Pod anständig erreichbar war.

"Erreichbar" ist hier auch der das tragische Stichwort. Denn die Nodes waren zwar online, konnten aber nicht anständig miteinander kommunizieren. Ein schneller Blick auf diverse von Google vorgeschlagene Websites sagten mir, dass ich mit dem Problem nicht allein war. Grund dafür waren anscheinend Unstimmigkeiten mit einer Netzwerksoftware zur Kommunikation mit Kubernetes (bei mir war es: flannel). Etliche Versuche später (es wurde immer dazu geraten unterschiedliche Versionen der flannelkonfig zu laden), starteten sämtliche Nodes, der Pod für die Netzwerkkommunikation sowie der Proxy und blieben auch auf dem Status "ready". So weit, so gut.

Allerdings traf das leider nicht auf den Pine64 zu. Denn anscheinend gibt es ein Problem bei der Architekturerkennung. Dieses ist leider auch ein bekanntes "Feature", sodass ich den Pine64 leider aus dem Cluster entfernen musste.

Mein erster Pod, Container, whatever

Nach etlichen Versuchen mit diversen Containern habe ich mich dann dazu entschlossen erst mal eine einfache Aufgabe zu meistern. Hierfür hielt ich es für praktisch erst mal ein Pod/Container zu betreiben, der keinerlei Abhängigkeiten und Volumes benötigt. Ich wollte erst einmal ein grundsätzliches Feature ans Laufen bekommen, weswegen ich mich für eine "einfache" Inbetriebnahme eines Tomcat Servers entschieden habe. Aber spätestens jetzt wurde es kompliziert. Denn meine vorherigen Tests ließen noch etliche Pods laufen, die ich nicht beenden konnte... und welche rein zufällig meine weiteren Experimente blockierten. Habe ich ein Pod beendet, wurde dieser wie von Geisterhand erneut gestartet. Hier kam ich das erste Mal in Kontakt mit den Unterschieden von

  • Pod
  • Service
  • Deployment

Von wundersamer Hand wurde kubectl delete pod [podname] zwar ausgeführt, aber bei der nächsten Kontrolle, wird der aktuelle Pod beendet, der selbe aber unter neuen ID neu gestartet. Erst nach einiges an Recherche(siehe: hier) habe ich herausgefunden, dass ich erst das dazugehörige Deployment löschen muss, um auch den Pod endgültig los zu werden.

Nachdem nun das Problem gelöst wurde, machte ich mich daran eine Kubernetes-gerechte File für die Inbetriebname des Tomcat-Servers zu erstellen. Hierbei kam folgendes heraus:

apiVersion: apps/v1
kind: Deployment
metadata:
   name: tomcat
spec:
   selector:
     matchLabels:
       run: tomcat
   template:
     metadata:
       labels:
         run: tomcat
     spec:
       containers:
         - name: tomcat
           image: tomcat:8.0
           ports:
             - containerPort: 8080

Die File (tomcat.yaml) konnte ich nun mit kubectl apply -f tomcat.yaml nutzen, um mein Deployment "tomcat" zu erstellen. Hiermit wird das image tomcat:8.0 runtergeladen, gestartet und es lauscht ab dann auf Port 8080. Jetzt bin ich in meinem Wahn davon ausgegangen, dass der Pod auch auf Port 8080 ausgeführt. Leider habe ich erst später nachlesen können, dass Kubernetes kein Portmapping (!!!) durchführt. Es bedeutet also, dass der Pod auf separaten Ports ausgeführt wird. Den Port ermittelt man z.B., indem man sich das betreffende Deployment mit kubectl describe deployment [name] anschaut. Bei mir war es dann der Port 31805. Der Ausgabe kann man im Übrigen auch die IP-Adresse des jeweiligen Nodes entnehmen (falls man nur einen betreiben sollte). Ein kurzes curl bzw. der Aufruf im Browser zeigte dann auch schon das gewünschte Ergebnis.

caa4554c-5451-42f1-a915-baacc65e8f06

Fazit

"Mal eben schnell machen" war bei mir mit Kubernetes nicht. Zwar war mir die Arbeitsweise von Docker wohl bekannt. Aber Kubernetes ist in seiner Gesamtheit wesentlich komplexer als ich es mir gedacht habe. Sicherlich lohnt es sich, auch für kleinere private Experimente, einen Cluster aufzubauen. Allerdings sollte hierfür eine Vielzahl an Lernzeit, aktives googlen oder intensives Studieren der Dokumentation eingeplant werden. Möglicherweise beruhten eine Vielzahl meiner Probleme auf die jeweilige Architektur der Rasberrys. Denn x86/x64 ist wesentlich prominenter. Aber die Rasberrys sind nunmal die günstigsten Single-Board-Computer (SBCs) auf dem Markt und damit am interessantesten für solch ein Projekt. Alles in Allem werde ich mir früher oder später noch 1-2 Rasberry Pi4 anschaffen, um hier noch etwas flexibler testen zu können. Und vor allem mit mehreren Nodes...

Literatur

Production-Grade Container Orchestration
Kubernetes (K8s) ist ein Open-Source-System zur Automatisierung der Bereitstellung, Skalierung und Verwaltung von containerisierten Anwendungen. Es gruppiert Container, aus denen sich eine Anwendung zusammensetzt, in logische Einheiten, um die Verwaltung und Erkennung zu erleichtern. Kubernetes baut…
Newest ‘kubernetes’ Questions
Stack Overflow | The World’s Largest Online Community for Developers
balenaEtcher - Home
A cross-platform tool for flashing images to SD cards & USB drives.

https://blog.hypriot.com/downloads/

https://kubernetes.io/de/docs/reference/kubectl/cheatsheet/

Kubernetes Cheat Sheet – Linux Academy
This Kubernetes Cheat Sheet is meant to get you started with performing commands in Kubernetes and provide all the basic commands at a quick glance.