Eigener Server-Cluster: Diese Grundlagen zum Aufbau solltest du über das Clustering wissen (mit und ohne Kubernetes)

Als Video ansehen
Bereitgestellt über YouTube

Eigener Server-Cluster: Diese Grundlagen zum Aufbau solltest du über das Clustering wissen (mit und ohne Kubernetes)

Im ersten Beitrag haben wir einen sogenannten „Single-Node“ Kubernetes-Cluster eingerichtet. Er bietet keine Lastverteilung oder gar Ausfallsicherheit und ist daher streng genommen gar kein Cluster. Für Test- und Entwicklungszwecke reicht das oft. Wer aber produktiv mit einem echten Cluster arbeiten möchte, braucht zwangsläufig mehrere Geräte. Auch das lässt sich mit Raspberry Pis umsetzen. Wobei das nur eine Möglichkeit ist. Wer X86 Systeme hat, kann die natürlich ebenfalls verwenden. Der Pi ist hier eine preiswerte und kompakte Alternative. Ein Knoten ist im folgenden ein Kubernetes-Server, also ein Raspberry Pi oder eine andere Maschine.

In diesem ersten Teil soll es um die Planung und den hardwareseitigen Aufbau des Clusters gehen. Später schauen wir uns die Softwareseite an, wie man mit K3s einen Kubernetes-Cluster aufbauen kann. Eventuell alternativ auch den manuellen Weg ohne Kubernetes.

Was ist ein Cluster und welche Vorteile/Nachteile bietet er?

Ein Cluster ist eine Verbund von mehreren Systemen (meist Knoten genannt), die zu einer Gruppe verknüpft werden und sich i.d.R gegenseitig überwachen. Das können Raspberry Pis sein, aber eben so jegliche andere physische oder virtuelle Server. Innerhalb dieses Clusters betreibt man die gewünschten Anwendungen. Das können z.B. Datenbanken oder Webanwendungen sein, aber auch andere Aufgaben wie Berechnungen, Crawler und so weiter.

Die Vorteile liegen in der Leistung und Skalierbarkeit, da man die Last auf mehrere Systeme aufteilen und bei Bedarf um weitere Knoten erweitern kann. Durch einen Cluster kann man auch Hochverfügbarkeit erreichen. Fällt ein Knoten aus oder ist wegen Wartungsarbeiten (z.B. Aktualisierungen) nicht verfügbar, können die restlichen Knoten übernehmen, sodass es für den Benutzer zu keinem Ausfall der Anwendung kommt.

Je nach den gewünschten Aufgaben kann man den Schwerpunkt auf Lastverteilung oder Redundanz setzen. Vor allem bei der Ausfallsicherheit wird man den Cluster etwas überdimensionieren, damit Ausfälle kompensiert werden können. Produktiv würde man außerdem die verschiedenen Knoten trennen. Mindestens auf unterschiedliche physische Maschinen, am besten aber auch geografisch.

Damit werden auch bereits die Nachteile deutlich: Man benötigt mehrere Systeme, die Installation wird komplexer und damit auch aufwändiger in der Wartung. Produktiv werden Cluster daher eher für große und/oder wichtige Systeme aufgesetzt. Privat ist das meist überdimensioniert. Aber eine Testumgebung kann natürlich dennoch sehr interessant sein, um sich in die Thematik einzuarbeiten und Praxiserfahrung zu sammeln.

In einem eigenen Beitrag werden wir einen Kubernetes-Cluster aufsetzen. Obwohl der Schwerpunkt darauf liegt, gilt vieles generell für Cluster.

Wo liegen die Daten?

Nahezu jede Anwendung arbeitet mit Daten. In einem Cluster muss man daher berücksichtigen, welche Daten es gibt und wo diese liegen. Vor allem für Hochverfügbarkeit ist das sehr wichtig. Ein einfaches Beispiel: Ein Webserver liefert statische Daten aus. Diese Dateien können auf einem Knoten liegen und z.B. per SSHFS von den anderen Servern gemoutet werden. Aber: Das System ist dann der einzelne Ausfallpunkt (Single Point of Failture). Ist dieser Knoten nicht verfügbar, kann auch der andere Server nichts ausliefern, obwohl er funktioniert – weil ihm ja die Daten fehlen.

Ein Cluster-Dateisystem oder zumindest Netzwerk-Dateisystem können daher sinnvoll oder gar notwendig sein. Vor allem bei Kubernetes ist diese Frage essenziell, da Kubernetes die Anwendungen eigenständig verteilt. Eine Anwendung fest an einen Knoten zu binden, ist eher die Ausnahme und schränkt die Flexibilität ein. Schließlich kann das Programm dann ja eben nicht woanders gestartet werden, obwohl genug andere Knoten verfügbar wären.

Wer hier nicht aufpasst, hat schnell einen versteckten einzelnen Ausfallpunkt als Abhängigkeit seines Clusters. Das kann z.B. auch ein einzelner NFS-Server sein, auf dem sämtliche Knoten ihre Daten ablegen. Wobei das natürlich nur dann ein Problem ist, wenn man Ausfallsicherheit erreichen möchte. Falls es lediglich darum geht Last zu verteilen, kann das – vor allem privat oder zu Testzwecken – völlig ausreichen.

Wie kommt man auf die Dienste der Cluster-Knoten?

Diese Frage ist vor allem dann interessant, wenn man einen Dienst anbietet, auf den von außerhalb des Clusters zugegriffen werden soll – wie z.B. Webserver oder Datenbanken. Teilweise kann man in der Anwendung mehrere Hostnamen oder IPs angeben und es wird automatisch anhand verschiedener Bedingungen gewechselt. Oft ist das aber nicht der Fall und wir brauchen eine zentrale Instanz, welche die „Weichen“ stellt. Im Falle einer Lastverteilung etwa soll diese Instanz die Anfragen gleichmäßig auf die Knoten aufteilen. Sinnvoll ist auch zu prüfen, ob die Knoten funktionieren und keine Anfragen an Knoten zu übergeben, die wir als fehlerhaft oder offline identifiziert haben.

Eine solche Instanz heißt Load Balancer. Er muss auch redundant sein, wenn wir Hochverfügbarkeit möchten – ansonsten ist der Lastverteiler unser einzelner Ausfallpunkt. Hier wird es dann wieder komplexer: Man braucht eine Floating IP. Diese IP ist nicht fix einem Server zugeordnet, wie es ansonsten üblich ist. Sondern sie kann „gleitet“ im Fehlerfall zu einem anderen System. Etwa zu einem zweiten Lastverteiler, wenn der erste Ausfällt. Für den Nutzer ändert sich dadurch nichts, da die IP-Adresse gleich bleibt. Es kommt somit zu keinen Verzögerungen und Caching-Problemen, wie es etwa bei DNS-Änderungen der Fall wäre.

Auch hier sollte man zuerst überlegen, was man wirklich braucht. Wenn es nicht gerade darum geht Floating IPs auszuprobieren, reicht privat und für Testzwecke eine einzelne Instanz aus.

Planung: Lastverteilung oder Hochverfügbarkeit – Wie viele Raspberry Pis brauche ich?

Man sollte sich zunächst Gedanken machen, was man mit dem Cluster in erster Linie erreichen möchte. Wenn man nur die Last aufteilen möchte, reicht im einfachsten Falle bereits ein zweiter Pi. Für eine zustandslose HTML-Seite würde das ausreichen: 2 Webserver, ein Loadbalancer zur Lastverteilung, schon kann ein Server ausfallen und der andere übernimmt.

Für alle zustandsorientierten Anwendungen wird es aber komplexer. Das bedeutet: Die Anwendung arbeitet mit Daten, die aus einer vorherigen Operation stammen. Ein klassisches Beispiel sind Datenbanken. Darin speichert man Informationen, die erst später wieder abgerufen werden. Nahezu jede Webanwendung ist ebenfalls zustandsorientiert, etwa durch Sitzungen. Ein deutliches Beispiel wäre hier ein Onlineshop, der einen Warenkorb speichert, um den Kauf später abzuschließen.

Bei Datenbanken ist vor allem die Integrität von Daten wichtig. Man muss also sicherstellen, dass Änderungen an alle Instanzen verteilt werden und es nirgendwo fehlerhafte Informationen gibt. Dafür braucht es bestimmte Regeln. Die von Kubernetes verwendete Datenbank Etcd benötigt eine Mehrheit von Knoten, um sich beim replizieren auf einen Anführer zu einigen. Haben wir nur 2 Knoten und einer fällt aus, gibt es keine Mehrheit mehr. Ähnlich wie in einer Abstimmung kann es hier zu einem „Unentschieden“ kommen. Bei 3 Knoten können 2 eine Mehrheit bilden, sodass einer ausfallen kann. Den verwendeten Raft-Algorithmus kann man sich wie eine Wahl vorstellen: Alle verbleibenden Nodes wählen ihren neuen Anführer, die Mehrheit entscheidet.

Optimal ist daher eine ungerade Anzahl an Nodes bzw. Pis: Bei 4 Knoten darf nämlich ebenfalls nur einer ausfallen, da wir mit 2 verbleibenden Knoten keine Mehrheit mehr hätten. Auf der anderen Seite steigt aber grundsätzlich das Ausfallrisiko mit der Anzahl an Servern. Ein Cluster mit 3 Nodes wäre hinsichtlich Ausfallsicherheit daher besser als 4 Nodes. Oder man erweitert alternativ auf 5 Nodes, wodurch 2 davon ausfallen können.

Wer statt Kubernetes selbst clustern möchte, sollte sich über die Anforderungen und Konzepte der gewünschten Anwendung informieren. Diese muss natürlich in jedem Falle clusterfähig sein, auch ohne Kubernetes.

Master bzw. Control Plane und Worker Nodes

Als „Nodes“ bezeichnet Kubernetes keinen beliebigen Server, sondern die Worker Nodes: Auf Ihnen laufen die Pods, welche wiederum die gewünschten Anwendungen in Form von Containern betreiben – die sozusagen die Arbeitslast, also das was wir betreiben möchten.

Für einen Cluster reicht das aber nicht, wir benötigen auch mindestens einen Control Plane oder früher auch Master genannten Node. Er koordiniert den Cluster und entscheidet beispielsweise, auf welchem Worker Node ein Pod gestartet wird. In einer Produktivumgebung aus dem Leerbuch hat man mehrere Master Nodes, sodass diese hochverfügbar sind. Und sie sind von den Workern getrennt, d.H. insgesamt 6 Systeme (3x Master, 3x Worker).

Natürlich kann man hier – zu recht – argumentieren, dass dies für einige Szenarien übertrieben ist – und man derartige Hochverfügbarkeit vielleicht gar nicht braucht. Es gibt verschiedene Alternativen und Kompromisse. Man kann etwa Worker und Control Plane Rollen auf die gleichen Systeme installieren. Das ist vor allem bei Testsystemen und in kleineren Umgebungen gängig. Oder man trennt Master und Worker zwar, aber nutzt nur einen Control Plane und verzichtet damit auf Hochverfügbarkeit.

Leave a Reply