Vollwertiges Kubernetes von Grund auf auf Raspberry Pi

Vollwertiges Kubernetes von Grund auf auf Raspberry Pi

Vor kurzem hat ein bekanntes Unternehmen angekündigt, dass es seine Laptop-Serie auf die ARM-Architektur umstellt. Als ich diese Nachricht hörte, fiel mir ein, dass ich beim wiederholten Durchsehen der Preise für EC2 bei AWS auf die Graviton-Prozessoren mit sehr attraktiven Preisen gestoßen bin. Der Haken war natürlich, dass es ARM ist. Damals hätte ich nie gedacht, dass ARM etwas Ernstes ist…

Für mich war diese Architektur immer das Reich von Mobilgeräten und anderen IoT-Kleinigkeiten. „Echte“ Server auf ARM — das ist irgendwie ungewöhnlich, in mancher Hinsicht sogar verrückt… Doch ein neuer Gedanke setzte sich in meinem Kopf fest, also beschloss ich an einem Wochenende, herauszufinden, was man heute überhaupt auf ARM betreiben kann. Ich wollte mit etwas Vertrautem und Naheliegendem beginnen: einem Kubernetes-Cluster. Und nicht einfach mit irgendeinem „Cluster“, sondern alles „wie im Großen“ angehen, damit es so nah wie möglich an dem ist, was ich gewohnt bin in der Produktion.

Laut meiner Vorstellung sollte das Cluster aus dem Internet erreichbar sein, eine gewisse Webanwendung ausführen und mindestens ein Monitoring enthalten. Um diese Idee umzusetzen, werden ein paar (oder mehr) Raspberry Pi mindestens der Modellreihe 3B+ benötigt. Auch AWS wäre ein geeigneter Ort für die Experimente gewesen, aber ich war speziell an den „Himbeeren“ interessiert (die sowieso ungenutzt herumlagen). Also werden wir auf ihnen ein Kubernetes-Cluster mit Ingress, Prometheus und Grafana einrichten.

Vorbereitung der „Himbeeren“

Installation des Betriebssystems und SSH

Bei der Auswahl des Betriebssystems habe ich mir nicht allzu viele Gedanken gemacht: Ich habe einfach das aktuellste Raspberry Pi OS Lite mit der offiziellen Websiteheruntergeladen. Dort ist auch die Installationsdokumentation verfügbar,, die auf allen Knoten des zukünftigen Clusters ausgeführt werden muss. Danach sind die folgenden Schritte (auch auf allen Knoten) erforderlich.

Nach dem Anschließen eines Monitors und einer Tastatur müssen zuerst das Netzwerk und SSH konfiguriert werden:

  1. Für den Betrieb des Clusters muss der Master unbedingt eine statische IP-Adresse haben, während die Arbeitsknoten das nach eigenem Ermessen entscheiden können. Ich bevorzugte überall statische Adressen aus Gründen der einfachen Konfiguration.
  2. Die statische Adresse kann im Betriebssystem konfiguriert werden (im Datei /etc/dhcpcd.conf gibt es ein passendes Beispiel) oder durch Fixierung des Leasings im DHCP-Server des verwendeten (in meinem Fall des heimischen) Routers.
  3. Der SSH-Server wird einfach in raspi-config aktiviert (Interfacing options → ssh).

Nachdem dies erledigt ist, kann man sich per SSH anmelden (der Standardlogin ist pi, und das Passwort ist raspberry oder das, welches geändert wurde) und mit der Konfiguration fortfahren.

Weitere Einstellungen

  1. Wir konfigurieren den Hostnamen. In meinem Beispiel werden verwendet pi-control und pi-worker.
  2. Überprüfen wir, ob das Dateisystem auf die gesamte Festplatte erweitert ist (df -h /). Bei Bedarf kann es mit raspi-config erweitert werden.
  3. Wir ändern das Standardpasswort des Benutzers in raspi-config.
  4. Wir deaktivieren die Swap-Datei (das ist eine Anforderung von Kubernetes; wenn Sie an weiteren Details zu diesem Thema interessiert sind, siehe Issue #53533):
    dphys-swapfile swapoff
    systemctl disable dphys-swapfile
  5. Wir aktualisieren die Pakete auf die neuesten Versionen:
    apt-get update && apt-get dist-upgrade -y
  6. Wir installieren Docker und zusätzliche Pakete:
    apt-get install -y docker docker.io apt-transport-https curl bridge-utils iptables-persistent

    Bei der Installation von iptables-persistent muss man die iptables-Einstellungen für ipv4 speichern, und in der Datei /etc/iptables/rules.v4 — Regeln zur Kette FORWARD, so:

    # Generated by xtables-save v1.8.2 on Sun Jul 19 00:27:43 2020
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [0:0]
    -A FORWARD -s 10.1.0.0/16  -j ACCEPT
    -A FORWARD -d 10.1.0.0/16  -j ACCEPT
    COMMIT
  7. Jetzt müssen wir nur noch neu starten.

Jetzt ist alles bereit für die Installation des Kubernetes-Clusters.

Kubernetes-Installation

An diesem Punkt habe ich absichtlich alle meine und unsere firmeneigenen Entwicklungen zur Automatisierung der Installation und Konfiguration des K8s-Clusters zurückgestellt. Stattdessen nutzen wir die offizielle Dokumentation von kubernetes.io (leicht ergänzt um Kommentare und Abkürzungen).

Wir fügen das Kubernetes-Repository hinzu:

curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
cat <<EOF | sudo tee /etc/apt/sources.list.d/kubernetes.list
deb https://apt.kubernetes.io/ kubernetes-xenial main
EOF
sudo apt-get update

Daraufhin schlägt die Dokumentation vor, das CRI (Container Runtime Interface) zu installieren. Da Docker bereits installiert ist, fahren wir fort und installieren die Hauptkomponenten:

sudo apt-get install -y kubelet kubeadm kubectl kubernetes-cni

Beim Schritt zur Installation der Hauptkomponenten habe ich sofort kubernetes-cni, das für den Betrieb des Clusters erforderlich ist, hinzugefügt. Und hier gibt es einen wichtigen Punkt: Das Paket kubernetes-cni erstellt aus irgendeinem Grund das Standardverzeichnis für die CNI-Schnittstelleneinstellungen nicht, weshalb ich es manuell erstellen musste:

mkdir -p /etc/cni/net.d

Für den Betrieb des Network-Backends, auf das wir später eingehen, ist es notwendig, das CNI-Plugin nachzuinstallieren. Ich habe mich für das mir vertraute und verständliche Plugin portmap entschieden (die vollständige Liste finden Sie unter Dokumentation):

curl -sL https://github.com/containernetworking/plugins/releases/download/v0.7.5/cni-plugins-arm-v0.7.5.tgz | tar zxvf - -C /opt/cni/bin/ ./portmap

Kubernetes-Konfiguration

Knoten mit Control Plane

Die Installation des Clusters selbst ist relativ einfach. Um diesen Prozess zu beschleunigen und sicherzustellen, dass die Kubernetes-Images verfügbar sind, kann man vorher Folgendes ausführen:

kubeadm config images pull

Jetzt führen wir die eigentliche Installation durch — wir initialisieren die Control Plane des Clusters:

kubeadm init --pod-network-cidr=10.1.0.0/16 --service-cidr=10.2.0.0/16 --upload-certs

Bitte beachten Sie, dass die Subnetze für Dienste und Pods sich weder gegenseitig noch mit bestehenden Netzwerken überschneiden dürfen.

Am Ende wird uns eine Nachricht angezeigt, dass alles gut ist, und es wird außerdem erklärt, wie man die Arbeitsknoten mit dem Control Plane verbindet:

Ihr Kubernetes Control-Plane wurde erfolgreich initialisiert!
Um Ihren Cluster zu nutzen, müssen Sie Folgendes als regulärer Benutzer ausführen:
 mkdir -p $HOME/.kube
 sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
 sudo chown $(id -u):$(id -g) $HOME/.kube/config
Jetzt sollten Sie ein Pod-Netzwerk für den Cluster bereitstellen.
Führen Sie "kubectl apply -f [podnetwork].yaml" mit einer der Optionen aus, die unter:
 https://kubernetes.io/docs/concepts/cluster-administration/addons/
 aufgeführt sind.
Sie können jetzt beliebig viele Control-Plane-Knoten beitreten, indem Sie den folgenden Befehl auf jedem als Root ausführen:
 kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
   --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050 
   --control-plane --certificate-key 72a3c0a14c627d6d7fdade1f4c8d7a41b0fac31b1faf0d8fdf9678d74d7d2403
Bitte beachten Sie, dass der Zertifikatschlüssel Zugriff auf sensible Cluster-Daten gewährt, bewahren Sie ihn geheim!
Als Sicherheitsmaßnahme werden die hochgeladenen Zertifikate in zwei Stunden gelöscht; falls erforderlich, können Sie
"kubeadm init phase upload-certs --upload-certs" verwenden, um die Zertifikate anschließend erneut zu laden.
Dann können Sie beliebig viele Arbeitsknoten beitreten, indem Sie Folgendes auf jedem als Root ausführen:
kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
   --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050

Wir werden die Empfehlungen zur Hinzufügung der Konfiguration für den Benutzer umsetzen. Ich empfehle außerdem, gleich die Autovervollständigung für kubectl hinzuzufügen:

 kubectl completion bash > ~/.kube/completion.bash.inc
 printf "
 # Kubectl Shell-Vervollständigung
 source '$HOME/.kube/completion.bash.inc'
 " >> $HOME/.bash_profile
 source $HOME/.bash_profile

An diesem Punkt kann man bereits den ersten Knoten im Cluster sehen (auch wenn er noch nicht bereit ist):

root@pi-control:~# kubectl get no
NAME         STATUS     ROLES    AGE   VERSION
pi-control   NotReady   master   29s   v1.18.6

Netzwerkkonfiguration

Wie in der nach der Installation angezeigten Nachricht erwähnt, muss nun ein Netzwerk im Cluster installiert werden. In der Dokumentation stehen Calico, Cilium, contiv-vpp, Kube-router und Weave Net zur Auswahl… Hier bin ich von der offiziellen Anleitung abgewichen und habe die für mich vertrautere und verständlichere Option gewählt: flannel im host-gw-Modus (weitere Informationen zu den verfügbaren Backends finden Sie in der Projektdokumentation).

Es ist recht einfach, ihn im Cluster zu installieren. Zunächst laden wir die Manifeste herunter:

wget https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml

Dann ändern wir in den Einstellungen den Typ von vxlan auf host-gw:

sed -i 's/vxlan/host-gw/' kube-flannel.yml

… und das Pod-Netzwerk — vom Standardwert auf das, das während der Clusterinitialisierung angegeben wurde:

sed -i 's#10.244.0.0/16#10.1.0.0/16#' kube-flannel.yml

Danach erstellen wir die Ressourcen:

kubectl create -f kube-flannel.yml

Fertig! Nach einiger Zeit wechselt der erste Knoten K8s in den Status Bereit:

NAME         STATUS   ROLES    AGE   VERSION
pi-control   Ready    master   2m    v1.18.6

Hinzufügen eines Arbeitsknotens

Jetzt kann ein Worker hinzugefügt werden. Dazu muss man nach der Installation von Kubernetes gemäß dem oben beschriebenen Szenario einfach den zuvor erhaltenen Befehl ausführen:

kubeadm join 192.168.88.30:6443 --token a485vl.xjgvzzr2g0xbtbs4 
    --discovery-token-ca-cert-hash sha256:9da6b05aaa5364a9ec59adcc67b3988b9c1b94c15e81300560220acb1779b050

Damit kann man annehmen, dass der Cluster bereit ist:

root@pi-control:~# kubectl get no
NAME         STATUS   ROLES    AGE    VERSION
pi-control   Ready    master   28m    v1.18.6
pi-worker    Ready       2m8s   v1.18.6

Ich hatte nur zwei Raspberry Pi zur Verfügung, also wollte ich keine davon nur für den Control Plane abgeben. Deshalb habe ich den automatisch eingerichteten Taint vom Knoten pi-control entfernt, indem ich Folgendes ausgeführt habe:

root@pi-control:~# kubectl edit node pi-control

… und die Zeilen entfernt:

 - effect: NoSchedule
   key: node-role.kubernetes.io/master

Ausstattung des Clusters mit dem erforderlichen Minimum

Zunächst benötigen wir Helm. Natürlich kann man alles auch ohne es machen, aber Helm ermöglicht es, einige Komponenten ganz ohne Dateiänderungen nach eigenem Ermessen zu konfigurieren. Im Grunde ist es einfach eine Binärdatei, die «kein Brot verlangt».

Also gehen wir zu helm.sh in den Bereich docs/installation und führen den Befehl von dort aus aus:

curl -s https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

Danach fügen wir das Chart-Repository hinzu:

helm repo add stable https://kubernetes-charts.storage.googleapis.com/

Jetzt installieren wir die Infrastrukturkomponenten gemäß der Planung:

  • Ingress-Controller;
  • Prometheus;
  • Grafana;
  • cert-manager.

Ingress-Controller

Die erste Komponente — Ingress-Controller — wird ziemlich einfach installiert und ist „aus der Box“ einsatzbereit. Dazu reicht es, in den Bereich Bare-Metal auf der Website zu gehen und den Installationsbefehl von dort aus auszuführen:

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yaml

In diesem Moment begannen jedoch die Raspberry Pi, Schwierigkeiten zu bereiten und an den disk IOPS zu kratzen. Das liegt daran, dass zusammen mit dem Ingress-Controller eine große Anzahl an Ressourcen installiert wird, viele API-Anfragen ausgeführt werden und entsprechend viele Daten in etcd geschrieben werden. Kurz gesagt, entweder ist die 10 Klasse Speicherkarte nicht sehr leistungsfähig, oder die SD-Karten sind generell für diese Last nicht ausreichend. Dennoch hat nach etwa 5 Minuten alles gestartet.

Ein Namespace wurde erstellt und darin erschien der Controller sowie alles, was er benötigt:

root@pi-control:~# kubectl -n ingress-nginx get pod
NAME                                        READY   STATUS      RESTARTS   AGE
ingress-nginx-admission-create-2hwdx        0/1     Completed   0          31s
ingress-nginx-admission-patch-cp55c         0/1     Completed   0          31s
ingress-nginx-controller-7fd7d8df56-68qp5   1/1     Running     0          48s

Prometheus

Die nächsten beiden Komponenten lassen sich recht einfach über Helm aus dem Chart-Repo installieren.

Finden Sie Prometheus, erstellen wir den Namespace und installieren wir ihn:

helm search repo stable | grep prometheus
kubectl create ns monitoring
helm install prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"}

Standardmäßig bestellt Prometheus zwei Festplatten: eine für die Daten von Prometheus selbst und eine für die Daten von AlertManager. Da im Cluster keine Storage-Class erstellt wurde, werden keine Festplatten angefordert und die Pods können nicht gestartet werden. Bei Bare-Metal-Installationen von Kubernetes verwenden wir normalerweise Ceph RBD, aber bei einem Raspberry Pi ist das deutlich übertrieben.

Deshalb erstellen wir einfachen Local Storage auf Hostpath. Die Manifeste für das Persistent Volume (PV) für den prometheus-server und den prometheus-alertmanager sind in der Datei prometheus-pv.yaml in Git-Repositories mit Beispielen für den Artikel. Das Verzeichnis für das PV muss zuvor auf der Festplatte des Knotens erstellt werden, an den wir Prometheus binden möchten: im Beispiel ist dies nodeAffinity nach Hostname pi-worker und darauf wurden die Verzeichnisse erstellt. /data/localstorage/prometheus-server und /data/localstorage/prometheus-alertmanager.

Wir laden das Manifest herunter (klonen) und fügen es in Kubernetes hinzu:

kubectl create -f prometheus-pv.yaml

An diesem Punkt bin ich zum ersten Mal auf ein Problem mit der ARM-Architektur gestoßen. Kube-state-metrics, das standardmäßig im Prometheus-Chart installiert wird, weigerte sich zu starten. Es gab einen Fehler aus:

root@pi-control:~# kubectl -n monitoring logs prometheus-kube-state-metrics-c65b87574-l66d8
standard_init_linux.go:207: exec user process caused "exec format error"

Das Problem ist, dass für kube-state-metrics ein Image des CoreOS-Projekts verwendet wird, das nicht für ARM gebaut wird:

kubectl -n monitoring get deployments.apps prometheus-kube-state-metrics -o=jsonpath={.spec.template.spec.containers[].image}
quay.io/coreos/kube-state-metrics:v1.9.7

Ich musste ein wenig googeln und fand zum Beispiel dieses Image. Um es zu verwenden, aktualisieren wir das Release und geben an, welches Image für kube-state-metrics verwendet werden soll:

helm upgrade prometheus --namespace monitoring stable/prometheus --set server.ingress.enabled=True --set server.ingress.hosts={"prometheus.home.pi"} --set kube-state-metrics.image.repository=carlosedp/kube-state-metrics --set kube-state-metrics.image.tag=v1.9.6

Wir überprüfen, dass alles gestartet ist:

root@pi-control:~# kubectl -n monitoring get po
NAME                                             READY   STATUS              RESTARTS   AGE
prometheus-alertmanager-df65d99d4-6d27g          2/2     Running             0          5m56s
prometheus-kube-state-metrics-5dc5fd89c6-ztmqr   1/1     Running             0          5m56s
prometheus-node-exporter-49zll                   1/1     Running             0          5m51s
prometheus-node-exporter-vwl44                   1/1     Running             0          4m20s
prometheus-pushgateway-c547cfc87-k28qx           1/1     Running             0          5m56s
prometheus-server-85666fd794-z9qnc               2/2     Running             0          4m52s

Grafana und cert-manager

Für die Grafiken und Dashboards installieren wir Grafana:

helm install grafana --namespace monitoring stable/grafana  --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}

Am Ende der Ausgabe wird gezeigt, wie man das Passwort für den Zugriff erhält:

kubectl get secret --namespace monitoring grafana -o jsonpath="{.data.admin-password}" | base64 --decode ; echo

Um Zertifikate zu bestellen, installieren wir cert-manager. Für die Installation wenden wir uns an Dokumentation, die entsprechende Befehle für Helm anbietet:

helm repo add jetstack https://charts.jetstack.io

helm install 
  cert-manager jetstack/cert-manager 
  --namespace cert-manager 
  --version v0.16.0 
  --set installCRDs=true

Für selbstsignierte Zertifikate im Heimgebrauch ist das völlig ausreichend. Wenn jedoch das gleiche Let’s Encrypt, benötigt man zusätzlich ein Cluster-Issuer. Details dazu finden Sie in unserem Artikel „SSL-Zertifikate von Let’s Encrypt mit cert-manager in Kubernetes».

Ich habe mich für die Option aus dem Beispiel in der Dokumentation entschieden, da ich der Meinung war, dass die Staging-Variante von LE ausreichend sein wird. Wir ändern die E-Mail im Beispiel, speichern sie in eine Datei und fügen sie zum Cluster hinzu (cert-manager-cluster-issuer.yaml):

kubectl create -f cert-manager-cluster-issuer.yaml

Jetzt können wir ein Zertifikat bestellen, zum Beispiel für Grafana. Dazu benötigen wir eine Domain und externen Zugriff auf den Cluster. Ich habe eine Domain, und der Verkehr wird über die Ports 80 und 443 auf meinem Heimrouter gemäß dem erstellten Service des Ingress-Controllers weitergeleitet:

kubectl -n ingress-nginx get svc
NAME                                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)                      AGE
ingress-nginx-controller             NodePort    10.2.206.61            80:31303/TCP,443:30498/TCP   23d

Der Port 80 wird in diesem Fall auf 31303 und der Port 443 auf 30498 weitergeleitet. (Die Ports werden zufällig generiert, daher werden sie bei Ihnen anders sein.)

Hier ist ein Beispiel für ein Zertifikat (cert-manager-grafana-certificate.yaml):

apiVersion: cert-manager.io/v1alpha2
kind: Certificate
metadata:
  name: grafana
  namespace: monitoring
spec:
  dnsNames:
    - grafana.home.pi
  secretName: grafana-tls
  issuerRef:
    kind: ClusterIssuer
    name: letsencrypt-staging

Fügen Sie es zum Cluster hinzu:

kubectl create -f cert-manager-grafana-certificate.yaml

Nach diesem Schritt wird eine Ingress-Ressource erstellt, über die die Validierung durch Let’s Encrypt erfolgt:

root@pi-control:~# kubectl -n monitoring get ing
NAME                        CLASS    HOSTS                        ADDRESS         PORTS   AGE
cm-acme-http-solver-rkf8l      grafana.home.pi      192.168.88.31   80      72s
grafana                        grafana.home.pi      192.168.88.31   80      6d17h
prometheus-server              prometheus.home.pi   192.168.88.31   80      8d

Nachdem die Validierung abgeschlossen ist, sehen wir, dass die Ressource certificate fertig ist und im oben genannten Geheimnis grafana-tls das Zertifikat und den Schlüssel enthält. Sie können sofort überprüfen, wer das Zertifikat ausgestellt hat:

root@pi-control:~# kubectl -n monitoring get certificate
NAME      READY   SECRET        AGE
grafana   True    grafana-tls   13m

root@pi-control:~# kubectl -n monitoring get secrets grafana-tls -ojsonpath="{.data['tls.crt']}" | base64 -d | openssl x509 -issuer -noout
issuer=CN = Fake LE Intermediate X1

Kommen wir zurück zu Grafana. Wir müssen ihren Helm-Release ein wenig anpassen, indem wir die TLS-Einstellungen gemäß dem erstellten Zertifikat ändern.

Dazu laden wir das Chart herunter, bearbeiten es und aktualisieren es aus dem lokalen Verzeichnis:

helm pull --untar stable/grafana

Wir bearbeiten die Datei grafana/values.yaml TLS-Parameter:

  tls:
    - secretName: grafana-tls
      hosts:
        - grafana.home.pi

Hier können wir auch Prometheus als Datenquelle:

datasources:
  datasources.yaml:
    apiVersion: 1
    datasources:
    - name: Prometheus
      type: prometheus
      url: http://prometheus-server:80
      access: proxy
      isDefault: true

Jetzt aktualisieren wir das Grafana-Chart aus dem lokalen Verzeichnis:

helm upgrade grafana --namespace monitoring ./grafana --set ingress.enabled=true --set ingress.hosts={"grafana.home.pi"}

Wir überprüfen, ob im Ingress grafana der Port 443 hinzugefügt wurde und die HTTPS-Verbindung verfügbar ist:

root@pi-control:~# kubectl -n monitoring get ing grafana
NAME CLASS HOSTS ADDRESS PORTS AGE
grafana  grafana.home.pi 192.168.88.31 80, 443 63m

root@pi-control:~# curl -kI https://grafana.home.pi
HTTP/2 302
server: nginx/1.19.1
date: Tue, 28 Jul 2020 19:01:31 GMT
content-type: text/html; charset=utf-8
cache-control: no-cache
expires: -1
location: /login
pragma: no-cache
set-cookie: redirect_to=; Path=/; HttpOnly; SameSite=Lax
x-frame-options: deny
strict-transport-security: max-age=15724800; includeSubDomains

Um Grafana in Aktion zu demonstrieren, können wir ein Dashboard für kube-state-metrics herunterladen und hinzufügen.So sieht es aus:

Vollwertiges Kubernetes von Grund auf auf Raspberry Pi

Ich empfehle auch, ein Dashboard für den Node Exporter hinzuzufügen: Es zeigt detailliert, was mit den "Raspberry Pis" (CPU-Auslastung, Speichernutzung, Netzwerkauslastung, Festplattennutzung usw.) passiert.

Danach denke ich, dass der Cluster bereit ist, Anwendungen zu empfangen und auszuführen!

Hinweis zur Erstellung

Für die Erstellung von Anwendungen für die ARM-Architektur gibt es mindestens zwei Optionen. Erstens kann man auf einem ARM-Gerät erstellen. Nachdem ich jedoch die aktuelle Auslastung von zwei Raspberry Pis betrachtet habe, wurde mir klar, dass sie auch die Erstellung nicht bewältigen werden. Daher habe ich mir eine neue Raspberry Pi 4 bestellt (sie ist leistungsstärker und hat erstaunliche 4 GB RAM) – ich plane, darauf zu erstellen.

Die zweite Option ist die Erstellung eines Multi-Architektur-Docker-Images auf einer leistungsfähigeren Maschine. Dafür gibt es erweiterungen docker buildx. Wenn die Anwendung in einer kompilierbaren Sprache geschrieben ist, ist eine Cross-Kompilierung für ARM erforderlich. Ich werde nicht alle Einstellungen für diesen Ansatz beschreiben, da dies einen eigenen Artikel erfordern würde. Bei der Umsetzung dieses Ansatzes können "universelle" Images erreicht werden: Docker, das auf einer ARM-Maschine läuft, wird automatisch das für die Architektur entsprechende Image herunterladen.

Fazit

Das durchgeführte Experiment hat all meine Erwartungen übertroffen: [mindestens] „vanilla“ Kubernetes mit der notwendigen Basis funktioniert gut auf ARM, und bei seiner Konfiguration gab es nur ein paar kleine Nuancen.

Die Raspberry Pi 3B+ halten die CPU-Belastung aus, jedoch sind ihre SD-Karten ein offensichtlicher Flaschenhals. Kollegen haben mir gesagt, dass es in einigen Versionen die Möglichkeit gibt, von USB zu booten, wo man ein SSD anschließen kann: dann wird die Situation wahrscheinlich besser.

Hier ist ein Beispiel für die CPU-Auslastung bei der Installation von Grafana:

Vollwertiges Kubernetes von Grund auf auf Raspberry Pi

Für Experimente und "zum Ausprobieren" überträgt ein Kubernetes-Cluster auf „Raspberry Pi“ meiner Meinung nach viel besser die Eindrücke von der Nutzung als dasselbe Minikube, da alle Komponenten des Clusters sowohl installiert als auch „professionell“ arbeiten.

In der Zukunft habe ich die Idee, den gesamten CI/CD-Zyklus vollständig auf Raspberry Pi zu integrieren. Ich wäre auch erfreut, wenn jemand seine Erfahrungen mit der Einrichtung von K8s auf AWS Graviton teilen würde.

P.S. Ja, „Produktion“ könnte näher sein, als ich dachte:

Vollwertiges Kubernetes von Grund auf auf Raspberry Pi

P.P.S.

Lesen Sie auch in unserem Blog:

Quelle: habr.com

Zuverlässiges Hosting für Websites mit DDoS-Schutz kaufen, VPS VDS Server 🔥 Zuverlässiges Hosting für Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster