Abenteuer mit einem Home Kubernetes Cluster

Hinweis perev. : Der Autor des Artikels, Marshall Brekka, ist Systemdesign-Direktor bei Fair.com, das seine Anwendung für das Autoleasing anbietet. In seiner Freizeit nutzt er seine umfangreiche Erfahrung gerne, um "Heim" -Probleme zu lösen, die wahrscheinlich keinen Geek überraschen (daher wird die Frage "Warum?" - in Bezug auf die unten beschriebenen Aktionen - a priori weggelassen). In seiner Veröffentlichung teilt Marshall die Ergebnisse der jüngsten Bereitstellung von Kubernetes auf ... ARM-Boards mit.



Wie viele andere Geeks habe ich im Laufe der Jahre eine Vielzahl von Entwicklungsboards wie den Raspberry Pi angesammelt. Und wie viele Geeks staubten sie sich in den Regalen mit dem Gedanken ab, dass sie eines Tages nützlich sein würden. Und jetzt ist für mich endlich dieser Tag gekommen!

Während der Winterferien traten mehrere Wochen außerhalb der Arbeit auf, in denen genügend Zeit blieb, um das gesamte angesammelte Eisen zu inventarisieren und zu entscheiden, was damit zu tun ist. Folgendes hatte ich:

  • RAID-Gehäuse mit 5 Laufwerken und USB3-Anschluss;
  • Himbeer-Pi-Modell B (OG-Modell);
  • CubbieBoard 1;
  • Banana Pi M1;
  • HP Netbook (2012?).

Von den 5 aufgelisteten Eisenkomponenten habe ich nur RAID und ein Netbook als temporäres NAS verwendet. Aufgrund der fehlenden USB3-Unterstützung im Netbook nutzte RAID jedoch nicht das volle Geschwindigkeitspotential.

Lebensziele


Da die Arbeit mit RAID bei Verwendung eines Netbooks nicht optimal war, habe ich die folgenden Ziele festgelegt, um die beste Konfiguration zu erzielen:

  1. NAS mit USB3 und Gigabit-Ethernet;
  2. Der beste Weg, um Software auf Ihrem Gerät zu verwalten
  3. (Bonus) die Möglichkeit, Multimedia-Inhalte von RAID auf Fire TV zu streamen.

Da keines der verfügbaren Geräte USB3 und Gigabit-Ethernet unterstützt, musste ich leider zusätzliche Einkäufe tätigen. Die Wahl fiel auf den ROC-RK3328-CC . Sie besaß alle notwendigen Spezifikationen und ausreichende Unterstützung für Betriebssysteme.

Nachdem ich meine Hardwarebedürfnisse gelöst hatte (und auf die Ankunft dieser Lösung gewartet hatte), wechselte ich zum zweiten Ziel.

Software auf dem Gerät verwalten


Zum Teil sind meine früheren Projekte im Zusammenhang mit Entwicklungsboards aufgrund unzureichender Berücksichtigung von Reproduzierbarkeits- und Dokumentationsproblemen gescheitert. Beim Erstellen der nächsten Konfiguration für meine aktuellen Anforderungen habe ich mir nicht die Mühe gemacht, die durchgeführten Schritte oder die Links zu den Blog-Posts aufzuschreiben, denen ich gefolgt bin. Und als nach Monaten oder Jahren etwas schief ging und ich versuchte, das Problem zu beheben, hatte ich kein Verständnis dafür, wie alles ursprünglich angeordnet war.

Also sagte ich mir, dass diesmal alles anders sein wird!



Und er wandte sich an die Tatsache, dass ich es gut genug weiß - an Kubernetes.

Obwohl K8s eine zu schwierige Lösung für ein eher einfaches Problem ist, bin ich nach fast drei Jahren der Verwaltung von Clustern mit verschiedenen Tools (meine eigenen, Kops usw.) bei meiner Hauptaufgabe mit diesem System sehr vertraut. Darüber hinaus schien die Bereitstellung von K8s außerhalb einer Cloud-Umgebung und sogar auf ARM-Geräten eine interessante Aufgabe zu sein.

Ich dachte auch, da die verfügbare Hardware nicht die erforderlichen Anforderungen für den NAS erfüllt, werde ich versuchen, zumindest einen Cluster daraus zusammenzusetzen, und möglicherweise kann eine Software, die nicht so ressourcenintensiv ist, auf älteren Geräten funktionieren.

Kubernetes auf ARM


Bei der Arbeit hatte ich nicht die Möglichkeit, das Dienstprogramm kubeadm zum Bereitstellen von Clustern zu verwenden. kubeadm entschied ich, dass es jetzt an der Zeit war, es in Aktion zu kubeadm .

Raspbian wurde als Betriebssystem ausgewählt, weil es für die beste Unterstützung meiner Boards bekannt ist.

Ich habe einen guten Artikel über das Einrichten von Kubernetes auf einem Raspberry Pi mit HypriotOS gefunden. Da ich nicht sicher war, ob HypriotOS für alle meine Boards verfügbar ist, habe ich diese Anleitung für Debian / Raspbian angepasst.

Erforderliche Komponenten


Zunächst mussten folgende Tools installiert werden:

  • Docker,
  • Kubelet
  • kubeadm,
  • kubectl.

Docker muss mit einem speziellen Skript installiert werden - einem praktischen Skript (wie für die Verwendung von Raspbian angegeben).

 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 

Danach habe ich die Kubernetes-Komponenten gemäß den Anweisungen im Hypriot-Blog installiert und sie so angepasst, dass für alle Abhängigkeiten bestimmte Versionen verwendet werden:

 curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list apt-get update apt-get install -y kubelet=1.13.1-00 kubectl=1.13.1-00 kubeadm=1.13.1-00 

Himbeer pi b


Die erste Schwierigkeit trat auf, als versucht wurde, einen Cluster auf dem Raspberry Pi B zu booten:

 $ kubeadm init Illegal instruction 

Es stellte sich heraus, dass Kubernetes die Unterstützung für ARMv6 entfernt hatte . Nun, ich habe auch CubbieBoard und Banana Pi.

Banane pi


Anfänglich schien dieselbe Abfolge von Aktionen für Banana Pi erfolgreicher zu sein. Der Befehl kubeadm init lief jedoch ab, während versucht wurde, auf die kubeadm init der kubeadm init zu warten:

 error execution phase wait-control-plane: couldn't initialize a Kubernetes cluster 

Als ich mit docker ps herausfand, was mit den Containern geschah, sah ich, dass sowohl der kube-controller-manager als auch der kube-scheduler mindestens 4-5 Minuten arbeiteten, aber der kube-api-server stand erst vor 1-2 Minuten auf:

 $ docker ps CONTAINER ID COMMAND CREATED STATUS de22427ad594 "kube-apiserver --au…" About a minute ago Up About a minute dc2b70dd803e "kube-scheduler --ad…" 5 minutes ago Up 5 minutes 60b6cc418a66 "kube-controller-man…" 5 minutes ago Up 5 minutes 1e1362a9787c "etcd --advertise-cl…" 5 minutes ago Up 5 minutes 

Offensichtlich starb der api-server oder der Strontium-Prozess tötete ihn und startete ihn neu.

Beim Überprüfen der Protokolle sah ich sehr standardmäßige Startverfahren - es gab eine Aufzeichnung über den Beginn des Abhörens des sicheren Ports und eine lange Pause, bevor zahlreiche Fehler bei TLS-Handshakes auftraten:

 20:06:48.604881 naming_controller.go:284] Starting NamingConditionController 20:06:48.605031 establishing_controller.go:73] Starting EstablishingController 20:06:50.791098 log.go:172] http: TLS handshake error from 192.168.1.155:50280: EOF 20:06:51.797710 log.go:172] http: TLS handshake error from 192.168.1.155:50286: EOF 20:06:51.971690 log.go:172] http: TLS handshake error from 192.168.1.155:50288: EOF 20:06:51.990556 log.go:172] http: TLS handshake error from 192.168.1.155:50284: EOF 20:06:52.374947 log.go:172] http: TLS handshake error from 192.168.1.155:50486: EOF 20:06:52.612617 log.go:172] http: TLS handshake error from 192.168.1.155:50298: EOF 20:06:52.748668 log.go:172] http: TLS handshake error from 192.168.1.155:50290: EOF 

Und bald danach beendet der Server seine Arbeit. Das Googeln führte zu einem solchen Problem , was auf einen möglichen Grund für den langsamen Betrieb kryptografischer Algorithmen auf einigen ARM-Geräten hinweist.

Ich ging weiter und dachte, dass der api-server möglicherweise zu viele wiederholte Anfragen von scheduler und controller-manager erhält.

Wenn Sie diese Dateien aus dem Manifest-Verzeichnis entfernen, wird kubelet angewiesen, die Ausführung der entsprechenden Pods zu stoppen:

 mkdir /etc/kubernetes/manifests.bak mv /etc/kubernetes/manifests/kube-scheduler.yaml /etc/kubernetes/manifests.bak/ mv /etc/kubernetes/manifests/kube-controller-mananger.yaml /etc/kubernetes/manifests.bak/ 

Das Anzeigen der neuesten api-server Protokolle zeigte, dass der Prozess nun api-server , jedoch nach etwa 2 Minuten immer noch zum Erliegen kam. Dann erinnerte ich mich, dass das Manifest eine Lebendigkeitsprobe mit Zeitüberschreitungen enthalten könnte, die für ein so langsames Gerät zu niedrige Werte haben.

Deshalb habe ich /etc/kubernetes/manifests/kube-api-server.yaml überprüft - und darin natürlich ...

 livenessProbe: failureThreshold: 8 httpGet: host: 192.168.1.155 path: /healthz port: 6443 scheme: HTTPS initialDelaySeconds: 15 timeoutSeconds: 15 

Der Pod wurde nach 135 Sekunden beendet ( initialDelaySeconds + timeoutSeconds * failureThreshold ). initialDelaySeconds auf 120 ...

Erfolg! Nun, Handshake-Fehler treten immer noch auf (vermutlich von Kubelet), aber der Start fand immer noch statt:

 20:06:54.957236 log.go:172] http: TLS handshake error from 192.168.1.155:50538: EOF 20:06:55.004865 log.go:172] http: TLS handshake error from 192.168.1.155:50384: EOF 20:06:55.118343 log.go:172] http: TLS handshake error from 192.168.1.155:50292: EOF 20:06:55.252586 cache.go:39] Caches are synced for autoregister controller 20:06:55.253907 cache.go:39] Caches are synced for APIServiceRegistrationController controller 20:06:55.545881 controller_utils.go:1034] Caches are synced for crd-autoregister controller ... 20:06:58.921689 storage_rbac.go:187] created clusterrole.rbac.authorization.k8s.io/cluster-admin 20:06:59.049373 storage_rbac.go:187] created clusterrole.rbac.authorization.k8s.io/system:discovery 20:06:59.214321 storage_rbac.go:187] created clusterrole.rbac.authorization.k8s.io/system:basic-user 

Als der api-server hochgefahren war, habe ich die YAML-Dateien für den Controller und den Scheduler zurück in das Manifest-Verzeichnis verschoben, wonach sie auch normal gestartet wurden.

Jetzt müssen Sie sicherstellen, dass der Download erfolgreich ist, wenn Sie alle Dateien im Quellverzeichnis livenessProbe : Reicht es aus, die zulässige Verzögerung bei der Initialisierung von livenessProbe ?

 20:29:33.306983 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.Service: Get https://192.168.1.155:6443/api/v1/services?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.434541 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.ReplicationController: Get https://192.168.1.155:6443/api/v1/replicationcontrollers?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.435799 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.PersistentVolume: Get https://192.168.1.155:6443/api/v1/persistentvolumes?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.477405 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1beta1.PodDisruptionBudget: Get https://192.168.1.155:6443/apis/policy/v1beta1/poddisruptionbudgets?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:33.493660 reflector.go:134] k8s.io/client-go/informers/factory.go:132: Failed to list *v1.PersistentVolumeClaim: Get https://192.168.1.155:6443/api/v1/persistentvolumeclaims?limit=500&resourceVersion=0: dial tcp 192.168.1.155:6443: i/o timeout 20:29:37.974938 controller_utils.go:1027] Waiting for caches to sync for scheduler controller 20:29:38.078558 controller_utils.go:1034] Caches are synced for scheduler controller 20:29:38.078867 leaderelection.go:205] attempting to acquire leader lease kube-system/kube-scheduler 20:29:38.291875 leaderelection.go:214] successfully acquired lease kube-system/kube-scheduler 

Ja, alles funktioniert, obwohl solche alten Geräte anscheinend nicht dazu gedacht waren, die Steuerebene zu starten, da wiederholte TLS-Verbindungen erhebliche Bremsen verursachen. So oder so - eine funktionierende Installation von K8s auf ARM wird empfangen! Gehen wir weiter ...

RAID-Montage


Da SD-Karten auf lange Sicht nicht für die Aufzeichnung geeignet sind, habe ich mich für einen zuverlässigeren Speicher für die flüchtigsten Teile des Dateisystems entschieden - in diesem Fall RAID. Es wurden 4 Abschnitte hervorgehoben:

  • 50 GB;
  • 2 × 20 GB;
  • 3,9 Tb.

Ich habe mir noch keinen konkreten Zweck für die 20-Gigabyte-Partitionen ausgedacht, aber ich wollte zusätzliche Möglichkeiten für die Zukunft lassen.

In der /etc/fstab für die 50-GB-Partition der Einhängepunkt als /mnt/root und für 3,9 TB - /mnt/raid . Danach habe ich die Verzeichnisse mit etcd und Docker auf die 50-GB-Partition gemountet:

 UUID=655a39e8-9a5d-45f3-ae14-73b4c5ed50c3 /mnt/root ext4 defaults,rw,user,auto,exec 0 0 UUID=0633df91-017c-4b98-9b2e-4a0d27989a5c /mnt/raid ext4 defaults,rw,user,auto 0 0 /mnt/root/var/lib/etcd /var/lib/etcd none defaults,bind 0 0 /mnt/root/var/lib/docker /var/lib/docker none defaults,bind 0 0 

Ankunft ROC-RK3328-CC


Als das neue Board ausgeliefert wurde, habe ich die notwendigen Komponenten für K8s darauf installiert (siehe Anfang des Artikels) und kubeadm init gestartet. Ein paar Minuten Wartezeit sind der Erfolg und die Ausgabe des join Befehls, der auf anderen Knoten ausgeführt werden soll.

Großartig! Keine Aufregung mit Auszeiten.

Und da RAID auch auf dieser Karte verwendet wird, müssen die Halterungen erneut konfiguriert werden. Um alle Schritte zusammenzufassen:

1. Mounten Sie die Festplatten in / etc / fstab


 UUID=655a39e8-9a5d-45f3-ae14-73b4c5ed50c3 /mnt/root ext4 defaults,rw,user,auto,exec 0 0 UUID=0633df91-017c-4b98-9b2e-4a0d27989a5c /mnt/raid ext4 defaults,rw,user,auto 0 0 /mnt/root/var/lib/etcd /var/lib/etcd none defaults,bind 0 0 /mnt/root/var/lib/docker /var/lib/docker none defaults,bind 0 0 

2. Installieren der Docker- und K8s-Binärdateien


 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 

 curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list apt-get update apt-get install -y kubelet=1.13.1-00 kubectl=1.13.1-00 kubeadm=1.13.1-00 

3. Konfigurieren eines eindeutigen Hostnamens (wichtig, da viele Knoten hinzugefügt werden)


 hostnamectl set-hostname k8s-master-1 

4. Kubernetes-Initialisierung


Ich lasse die Phase mit der Steuerebene weg, weil ich normale Pods auf diesem Knoten planen möchte:

 kubeadm init --skip-phases mark-control-plane 

5. Installieren Sie das Netzwerk-Plugin


Die Informationen dazu im Hypriot-Artikel waren etwas veraltet, da das Weave-Netzwerk-Plugin jetzt auch von ARM unterstützt wird :

 export KUBECONFIG=/etc/kubernetes/admin.conf kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')" 

6. Hinzufügen von Host-Labels


Auf diesem Knoten starte ich den NAS-Server, daher werde ich ihn mit Labels für eine mögliche zukünftige Verwendung im Scheduler markieren:

 kubectl label nodes k8s-master-1 marshallbrekka.raid=true kubectl label nodes k8s-master-1 marshallbrekka.network=gigabit 

Andere Knoten mit dem Cluster verbinden


Das Einrichten anderer Geräte (Banana Pi, CubbieBoard) war ebenso einfach. Für sie müssen Sie die ersten drei Schritte wiederholen (Ändern der Einstellungen für das Mounten von Festplatten / Flash-Medien, abhängig von ihrer Verfügbarkeit) und den Befehl kubeadm join anstelle von kubeadm init .

Suchen von Docker-Containern für ARM


Die meisten erforderlichen Docker-Container werden normalerweise auf einem Mac erstellt, für ARM ist dies jedoch etwas komplizierter. Nachdem ich viele Artikel über die Verwendung von QEMU für diese Zwecke gefunden hatte, kam ich dennoch zu dem Schluss, dass die meisten der von mir benötigten Anwendungen bereits zusammengestellt sind und viele von ihnen auf Linuxserver verfügbar sind .

Nächste Schritte


Da ich die Erstkonfiguration der Geräte immer noch nicht in einer von mir kubeadm automatisierten / skriptbasierten Form erhalten habe, habe ich zumindest eine Reihe grundlegender Befehle (Mounts, kubeadm und kubeadm ) verfasst und diese im Git-Repository dokumentiert. Die übrigen verwendeten Anwendungen erhielten auch YAML-Konfigurationen für K8s, die im selben Repository gespeichert sind. Daher ist es jetzt sehr einfach, die erforderliche Konfiguration von Grund auf neu zu erstellen.

In Zukunft möchte ich Folgendes erreichen:

  1. Master-Sites hoch verfügbar machen
  2. Hinzufügen von Überwachungen / Benachrichtigungen, um über Fehler in Komponenten informiert zu werden;
  3. Ändern Sie die DCHP-Einstellungen des Routers so, dass ein DNS-Server aus dem Cluster verwendet wird, um die Erkennung von Anwendungen zu vereinfachen (wer möchte sich die internen IP-Adressen merken?).
  4. Führen Sie MetalLB aus , um Clusterdienste an ein privates Netzwerk (DNS usw.) weiterzuleiten .


PS vom Übersetzer


Lesen Sie auch in unserem Blog:

Source: https://habr.com/ru/post/de435526/


All Articles