GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Kernkomponenten eines Kubernetes-Clusters

Kubernetes ist eine Open-Source-Plattform zur Verwaltung containerisierter Arbeitslasten und Dienste, die die deklarative Konfiguration und Automatisierung erleichtert. Der Name Kubernetes stammt ursprünglich aus dem Griechischen und bedeutet Steuermann oder Pilot. Es ist sowohl portabel als auch erweiterbar und verfügt über ein schnell wachsendes Ökosystem. Die Dienste und Tools von Kubernetes sind weit verbreitet.

In diesem Artikel werden wir eine 10.000-Fuß-Ansicht der Hauptkomponenten von Kubernetes durchgehen, von der Zusammensetzung der einzelnen Container bis hin zur Bereitstellung und Planung eines Containers in einem Pod für jeden der Worker. Es ist wichtig, alle Einzelheiten des Kubernetes-Clusters zu verstehen, um eine auf Kubernetes basierende Lösung als Orchestrator für containerisierte Anwendungen bereitstellen und entwerfen zu können.

Hier ist ein kurzer Überblick über die Dinge, die wir in diesem Artikel behandeln werden:

  • Komponenten des Steuerungsfelds
  • Die Komponenten des Kubernetes-Workers
  • Pods als Grundbausteine
  • Kubernetes-Dienste, Load-Balancer und Ingress-Controller
  • Kubernetes-Bereitstellungen und Daemon-Sets
  • Permanenter Speicher in Kubernetes

Die Kubernetes-Steuerungsebene

Auf den Kubernetes-Masterknoten befinden sich die Kerndienste der Steuerungsebene. nicht alle Dienste müssen sich auf demselben Knoten befinden; Aus Gründen der Zentralisierung und Praktikabilität werden sie jedoch häufig auf diese Weise bereitgestellt. Dies wirft offensichtlich Fragen zur Verfügbarkeit von Diensten auf; Sie können jedoch leicht überwunden werden, indem mehrere Knoten vorhanden sind und Lastausgleichsanfragen bereitgestellt werden, um einen hoch verfügbaren Satz von Master-Knoten zu erreichen .

Die Master-Knoten bestehen aus vier grundlegenden Diensten:

  • Der kube-apiserver
  • Der Kube-Scheduler
  • Der Kube-Controller-Manager
  • Die etcd-Datenbank

Master-Knoten können entweder auf Bare-Metal-Servern, virtuellen Maschinen oder einer privaten oder öffentlichen Cloud ausgeführt werden, es wird jedoch nicht empfohlen, Container-Workloads darauf auszuführen. Wir werden später mehr dazu sehen.

Das folgende Diagramm zeigt die Komponenten der Kubernetes-Masterknoten:

Der kube-apiserver

Der API-Server verbindet alles zusammen. Es ist die Front-End-REST-API des Clusters, die Manifeste zum Erstellen, Aktualisieren und Löschen von API-Objekten wie Diensten, Pods, Ingress und anderen empfängt.

Der kube-apiserver ist der einzige Dienst, mit dem wir sprechen sollten; Es ist auch das einzige, das in die etcd-Datenbank schreibt und mit ihr kommuniziert, um den Clusterstatus zu registrieren. Mit dem kubectl-Befehl senden wir Befehle, um damit zu interagieren. Das wird unser Schweizer Taschenmesser, wenn es um Kubernetes geht.

Der kube-controller-manager

Der kube-controller-manager-Daemon ist kurz gesagt eine Reihe von unendlichen Regelkreisen, die der Einfachheit halber in einer einzigen Binärdatei ausgeliefert werden. Es überwacht den definierten gewünschten Zustand des Clusters und stellt sicher, dass es erreicht und erfüllt wird, indem es alle Teile bewegt, die erforderlich sind, um es zu erreichen. Der kube-controller-manager ist nicht nur ein Controller; Es enthält mehrere verschiedene Schleifen, die verschiedene Komponenten im Cluster überwachen. Einige von ihnen sind der Dienst-Controller, der Namespace-Controller, der Dienstkonto-Controller und viele andere. Sie finden jeden Controller und seine Definition im Kubernetes GitHub-Repository:https://github.com/kubernetes/kubernetes/tree/master/pkg/controller.

Der kube-scheduler

Der kube-scheduler plant Ihre neu erstellten Pods auf Knoten mit genügend Speicherplatz, um die Ressourcenanforderungen der Pods zu erfüllen. Es hört im Grunde auf den Kube-Apiserver und den Kube-Controller-Manager auf neu erstellte Pods, die in eine Warteschlange gestellt und dann vom Planer für einen verfügbaren Knoten geplant werden. Die kube-scheduler-Definition finden Sie hier:https://github.com/kubernetes/kubernetes/blob/master/pkg/scheduler.

Neben Rechenressourcen liest der Kube-Scheduler auch die Affinitäts- und Anti-Affinitätsregeln der Knoten, um herauszufinden, ob ein Knoten diesen Pod ausführen kann oder nicht.

Die etcd-Datenbank

Die etcd-Datenbank ist ein sehr zuverlässiger konsistenter Schlüsselwertspeicher, der zum Speichern des Status des Kubernetes-Clusters verwendet wird. Es enthält den aktuellen Status der Pods, auf denen der Knoten ausgeführt wird, wie viele Knoten der Cluster derzeit hat, wie der Status dieser Knoten ist, wie viele Replikate der Bereitstellung ausgeführt werden, Dienstnamen und andere.

Wie bereits erwähnt, kommuniziert nur der kube-apiserver mit der etcd-Datenbank. Wenn der kube-controller-manager den Status des Clusters überprüfen muss, durchläuft er den API-Server, um den Status aus der etcd-Datenbank abzurufen, anstatt den etcd Store direkt abzufragen. Dasselbe passiert mit dem Kube-Scheduler, wenn der Scheduler bekannt geben muss, dass ein Pod gestoppt oder einem anderen Knoten zugewiesen wurde; es informiert den API-Server und der API-Server speichert den aktuellen Status in der etcd-Datenbank.

Mit etcd haben wir alle Hauptkomponenten für unsere Kubernetes-Masterknoten abgedeckt, sodass wir bereit sind, unseren Cluster zu verwalten. Aber ein Cluster besteht nicht nur aus Mastern; Wir benötigen immer noch die Knoten, die die schwere Arbeit leisten, indem sie unsere Anwendungen ausführen.

Kubernetes-Worker-Knoten

Die Worker-Knoten, die diese Aufgabe in Kubernetes ausführen, werden einfach als Knoten bezeichnet. Früher, um 2014, wurden sie Minions genannt, aber dieser Begriff wurde später durch Knoten ersetzt, da der Name mit den Terminologien von Salt verwirrend war und die Leute glauben ließ, dass Salt eine wichtige Rolle in Kubernetes spielt.

Diese Knoten sind der einzige Ort, an dem Sie Arbeitslasten ausführen, da es nicht empfehlenswert ist, Container oder Lasten auf den Masterknoten zu haben, da sie verfügbar sein müssen, um den gesamten Cluster zu verwalten. Die Knoten sind in Bezug auf die Komponenten sehr einfach; Sie benötigen nur drei Dienste, um ihre Aufgabe zu erfüllen:

  • Kubelet
  • Kube-Proxy
  • Containerlaufzeit

Sehen wir uns diese drei Komponenten etwas genauer an.

Das Kubelet

Das Kubelet ist eine Low-Level-Kubernetes-Komponente und eine der wichtigsten nach dem Kube-Apiserver; Diese beiden Komponenten sind für die Bereitstellung von Pods/Containern im Cluster unerlässlich. Das Kubelet ist ein Dienst, der auf den Kubernetes-Knoten ausgeführt wird und den API-Server für die Pod-Erstellung abhört. Das Kubelet ist nur für das Starten/Stoppen zuständig und stellt sicher, dass Container in Pods intakt sind; Das Kubelet kann keine Container verwalten, die nicht von ihm erstellt wurden.

Das Kubelet erreicht die Ziele, indem es über die Container Runtime Interface (CRI) mit der Container-Laufzeit kommuniziert . Das CRI bietet Pluggability für das Kubelet über einen gRPC-Client, der mit verschiedenen Containerlaufzeiten kommunizieren kann. Wie bereits erwähnt, unterstützt Kubernetes mehrere Container-Laufzeiten zum Bereitstellen von Containern und erreicht so eine so vielfältige Unterstützung für verschiedene Engines.

Sie können den Quellcode von kubelet über https://github.com/kubernetes/kubernetes/tree/master/pkg/kubelet.

überprüfen

Der Kube-Proxy

Der kube-proxy ist ein Dienst, der sich auf jedem Knoten des Clusters befindet und der die Kommunikation zwischen Pods, Containern und Knoten ermöglicht. Dieser Dienst überwacht den kube-apiserver auf Änderungen an definierten Diensten (der Dienst ist eine Art logischer Load Balancer in Kubernetes; wir werden später in diesem Artikel tiefer auf Dienste eingehen) und hält das Netzwerk über iptables-Regeln auf dem Laufenden, die den Datenverkehr weiterleiten die richtigen Endpunkte. Kube-Proxy richtet auch Regeln in iptables ein, die einen zufälligen Lastenausgleich zwischen Pods hinter einem Dienst durchführen.

Hier ist ein Beispiel für eine iptables-Regel, die vom kube-proxy erstellt wurde:

-A KUBE-SERVICES -d 10.0.162.61/32 -p tcp -m comment --comment "default/example:has no endpoints" -m tcp --dport 80 -j REJECT --reject-with icmp-port-unreachable

Beachten Sie, dass dies ein Dienst ohne Endpunkte ist (keine Pods dahinter).

Container-Laufzeit

Um Container hochfahren zu können, benötigen wir eine Container-Laufzeit . Dies ist die Basis-Engine, die die Container im Node-Kernel erstellt, damit unsere Pods ausgeführt werden können. Das Kubelet wird mit dieser Laufzeit kommunizieren und unsere Container bei Bedarf hochfahren oder stoppen.

Derzeit unterstützt Kubernetes jede OCI-kompatible Container-Laufzeit wie Docker, rkt, runc, runsc usw.

Sie können auf https://github.com/opencontainers/runtime-spec verweisen, um mehr über alle Spezifikationen auf der OCI-Git-Hub-Seite zu erfahren.

Nachdem wir nun alle Kernkomponenten untersucht haben, die einen Cluster bilden, werfen wir nun einen Blick darauf, was mit ihnen gemacht werden kann und wie Kubernetes uns dabei helfen wird, unsere containerisierten Anwendungen zu orchestrieren und zu verwalten.

Kubernetes-Objekte

Kubernetes-Objekte sind genau das:Sie sind logische persistente Objekte oder Abstraktionen, die den Zustand Ihres Clusters darstellen. Sie sind dafür verantwortlich, Kubernetes mitzuteilen, was Ihr gewünschter Zustand dieses Objekts ist, damit es ihn verwalten und sicherstellen kann, dass das Objekt vorhanden ist.

Um ein Objekt zu erstellen, muss es zwei Dinge haben:einen Status und seine Spezifikation. Der Status wird von Kubernetes bereitgestellt und ist der aktuelle Zustand des Objekts. Kubernetes verwaltet und aktualisiert diesen Status nach Bedarf, damit er Ihrem gewünschten Status entspricht. Das Spezifikationsfeld hingegen ist das, was Sie Kubernetes zur Verfügung stellen und das Sie ihm mitteilen, um das gewünschte Objekt zu beschreiben. Zum Beispiel das Image, das der Container ausführen soll, die Anzahl der Container dieses Images, die Sie ausführen möchten, und so weiter.

Jedes Objekt hat spezifische Spezifikationsfelder für die Art der Aufgabe, die es ausführt, und Sie stellen diese Spezifikationen in einer YAML-Datei bereit, die mit kubectl an den kube-apiserver gesendet wird, der sie in JSON umwandelt und als API-Anfrage sendet . Wir werden später in diesem Artikel tiefer in jedes Objekt und seine Spezifikationsfelder eintauchen.

Hier ist ein Beispiel für eine YAML-Datei, die an kubectl gesendet wurde:

Katze <

Die grundlegenden Felder der Objektdefinition sind die allerersten, und diese variieren nicht von Objekt zu Objekt und sind sehr selbsterklärend. Werfen wir einen kurzen Blick auf sie:

  • kind:Das kind-Feld teilt Kubernetes mit, welche Art von Objekt Sie definieren:ein Pod, ein Dienst, eine Bereitstellung usw.
  • apiVersion:Da Kubernetes mehrere API-Versionen unterstützt, müssen wir einen REST-API-Pfad angeben, an den wir unsere Definition senden möchten
  • Metadaten:Dies ist ein verschachteltes Feld, was bedeutet, dass Sie mehrere weitere Unterfelder für Metadaten haben, in die Sie grundlegende Definitionen wie den Namen Ihres Objekts schreiben, es einem bestimmten Namensraum zuweisen und ihm auch eine Bezeichnung zuweisen um Ihr Objekt mit anderen Kubernetes-Objekten zu verknüpfen

Wir sind jetzt also die am häufigsten verwendeten Felder und ihre Inhalte durchgegangen; Weitere Informationen zu den Kubernetes-API-Konventionen finden Sie unter https://github.com/kubernetes/community/blob/master/contributors/devel/api-conventions.md

Einige der Felder des Objekts können später geändert werden, nachdem das Objekt erstellt wurde, aber das hängt von dem Objekt und dem Feld ab, das Sie ändern möchten.

Im Folgenden finden Sie eine kurze Liste der verschiedenen Kubernetes-Objekte, die Sie erstellen können:

  • Pod
  • Lautstärke
  • Dienst
  • Bereitstellung
  • Ingress
  • Geheimnis
  • ConfigMap

Und es gibt noch viele mehr.

Lassen Sie uns einen genaueren Blick auf jedes dieser Elemente werfen.

Pods – die Basis von Kubernetes

Pods sind die grundlegendsten Objekte in Kubernetes und auch die wichtigsten. Alles dreht sich um sie; wir können sagen, dass Kubernetes für die Pods ist! Alle anderen Objekte sind hier, um ihnen zu dienen, und alle Aufgaben, die sie erledigen, bestehen darin, die Kapseln in den gewünschten Zustand zu versetzen.

Was ist also ein Pod und warum sind Pods so wichtig?

Ein Pod ist ein logisches Objekt, das einen oder mehrere Container zusammen auf demselben Netzwerk-Namespace, derselben Inter-Process-Communication (IPC), ausführt und manchmal, je nach Kubernetes-Version, dieselbe Prozess-ID (PID) Namensraum. Dies liegt daran, dass sie unsere Container betreiben und daher im Mittelpunkt der Aufmerksamkeit stehen werden. Der ganze Sinn von Kubernetes besteht darin, ein Container-Orchestrierer zu sein, und mit Pods machen wir die Orchestrierung möglich.

Wie bereits erwähnt, befinden sich Container auf demselben Pod in einer „Blase“, in der sie über localhost miteinander kommunizieren können, da sie lokal zueinander sind. Ein Container in einem Pod hat dieselbe IP-Adresse wie der andere Container, da sie sich einen Netzwerk-Namespace teilen, aber in den meisten Fällen werden Sie auf einer Eins-zu-Eins-Basis ausgeführt, d. h. ein einzelner Container pro Pod . Mehrere Container pro Pod werden nur in sehr spezifischen Szenarien verwendet, z. B. wenn eine Anwendung einen Helfer wie einen Daten-Pusher oder einen Proxy benötigt, der schnell und zuverlässig mit der primären Anwendung kommunizieren muss.

Sie definieren einen Pod genauso wie jedes andere Kubernetes-Objekt:über eine YAML-Datei, die alle Pod-Spezifikationen und -Definitionen enthält:

kind:PodapiVersion:v1metadata:name:hello-podlabels:  hello:podspec:  container:    - name:hello-container      image:alpine      args:      - echo      - "Hello World"

Lassen Sie uns die grundlegenden Pod-Definitionen durchgehen, die unter dem Spezifikationsfeld benötigt werden, um unseren Pod zu erstellen:

  • Container :Container ist ein Array; Daher haben wir eine Reihe von mehreren Unterfeldern darunter. Im Grunde definiert es die Container, die auf dem Pod ausgeführt werden. Wir können einen Namen für den Container, das Image, von dem ein Spin-off werden soll, und die Argumente oder Befehle angeben, die wir zur Ausführung benötigen. Der Unterschied zwischen Argumenten und Befehlen ist derselbe wie der Unterschied zwischen CMD und ENTRYPOINT. Beachten Sie, dass alle Felder, die wir gerade durchgegangen sind, für das Container-Array sind. Sie sind nicht direkt Teil der Spezifikation des Pods.
  • restartPolicy : Dieses Feld ist genau das:Es teilt Kubernetes mit, was mit einem Container zu tun ist, und es gilt für alle Container im Pod im Falle eines Exit-Codes von null oder ungleich null. Sie können zwischen den beiden Optionen Nie, Bei Fehler oder Immer wählen. Always ist der Standardwert, falls keine restartPolicy definiert ist.

Dies sind die grundlegendsten Spezifikationen, die Sie auf einem Pod deklarieren werden; Andere Spezifikationen erfordern etwas mehr Hintergrundwissen darüber, wie sie verwendet werden und wie sie mit verschiedenen anderen Kubernetes-Objekten interagieren. Wir werden später in diesem Artikel darauf zurückkommen; einige von ihnen sind wie folgt:

  • Lautstärke
  • Umschlag
  • Anschlüsse
  • dnsPolicy
  • initContainer
  • Knotenauswahl
  • Ressourcenlimits und Anfragen

Um die Pods anzuzeigen, die derzeit in Ihrem Cluster ausgeführt werden, können Sie kubectl get pods ausführen:

[email protected]:~$ kubectl get podsNAME      READY STATUS    RESTARTS AGEbusybox   1/1 Running   120 5d

Alternativ können Sie kubectl-describe-Pods ausführen, ohne einen Pod anzugeben. Dadurch wird eine Beschreibung jedes Pods gedruckt, der im Cluster ausgeführt wird. In diesem Fall ist es nur der Busybox-Pod, da er der einzige ist, der derzeit ausgeführt wird:

[E-Mail geschützt]:~ $ kubectl beschreiben Podsname:BusyBoxNameSpace:Standardpriorität:0PriorityClassName: Knoten:AKS-Agentpool-10515745-2/10.240.0.6Start Time:Mi, 19. September 2018 14:23:30 -0600LABELS:Annotations:        Status:             RunningIP:                 10.244.1.7Containers:busybox:[...] (Ausgabe zur besseren Lesbarkeit abgeschnitten)Events:Type    Reason Age                 From      Message---- -  ------ --- ----      -------Normal  Pulled 45s (x121 over 5d)  kubelet, aks-agentpool-10515745-2  Container-Image "busybox" bereits auf Maschine vorhandenNormal  Created 44s (x121 over 5d)  kubelet, aks-agentpool- 10515745-2 Container erstelltNormal Begonnen 44s (x121 über 5d) kubelet, aks-agentpool-10515745-2 Container gestartet

Pods sind sterblich. Sobald es stirbt oder gelöscht wird, können sie nicht wiederhergestellt werden. Seine IP und die Container, die darauf liefen, werden weg sein; sie sind völlig vergänglich. Die Daten auf den Pods, die als Volume bereitgestellt werden, können überleben oder nicht, je nachdem, wie Sie sie eingerichtet haben. Wenn unsere Pods sterben und wir sie verlieren, wie stellen wir dann sicher, dass alle unsere Microservices ausgeführt werden? Nun, Bereitstellungen sind die Antwort.

Bereitstellungen

Pods an sich sind nicht sehr nützlich, da es nicht sehr effizient ist, mehr als eine einzelne Instanz unserer Anwendung in einem einzelnen Pod auszuführen. Das Bereitstellen von Hunderten von Kopien unserer Anwendung auf verschiedenen Pods ohne eine Methode zum Suchen nach allen wird sehr schnell außer Kontrolle geraten.

Hier kommen Bereitstellungen ins Spiel. Bei Bereitstellungen können wir unsere Pods mit einem Controller verwalten. Auf diese Weise können wir nicht nur entscheiden, wie viele wir ausführen möchten, sondern wir können auch Updates verwalten, indem wir die Image-Version oder das Image selbst ändern, auf dem unsere Container ausgeführt werden. Bereitstellungen sind das, womit Sie die meiste Zeit arbeiten werden. Sowohl Bereitstellungen als auch Pods und alle anderen Objekte, die wir zuvor erwähnt haben, haben ihre eigene Definition in einer YAML-Datei:

apiVersion:apps/v1kind:Bereitstellungsmetadaten:Name:nginx-Bereitstellungslabels:   Bereitstellung:nginxspec:Replikate:3 Selektor:   Übereinstimmungslabels:     App:nginx-Vorlage:   Metadaten:     Labels:       App:nginx   Spezifikation:     Container:     - Name:nginx       Bild:nginx:1.7.9       Ports:       - containerPort:80

Beginnen wir mit der Erforschung ihrer Definition.

Am Anfang von YAML haben wir allgemeinere Felder wie apiVersion, kind und metadata. Aber unter Spezifikation finden wir die spezifischen Optionen für dieses API-Objekt.

Unter Spezifikation können wir die folgenden Felder hinzufügen:

Selektor :Mit dem Selector-Feld weiß die Bereitstellung, auf welche Pods sie abzielen soll, wenn Änderungen angewendet werden. Es gibt zwei Felder, die Sie unter dem Selektor verwenden werden: matchLabels und matchExpressions. Bei matchLabels verwendet der Selektor die Labels der Pods (Schlüssel/Wert-Paare). Beachten Sie, dass alle Labels, die Sie hier angeben, UND-verknüpft werden. Das bedeutet, dass der Pod alle Labels haben muss, die Sie unter matchLabels angeben.

Repliken :Hier wird die Anzahl der Pods angegeben, die die Bereitstellung benötigt, um über den Replikationscontroller ausgeführt zu werden. Wenn Sie beispielsweise drei Replikate angeben und einer der Pods stirbt, überwacht der Replikationscontroller die Replikatspezifikation als gewünschten Zustand und informiert den Planer, einen neuen Pod zu planen, da der aktuelle Status jetzt 2 ist, da der Pod starb.

RevisionHistoryLimit :Jedes Mal, wenn Sie eine Bereitstellung ändern, wird diese Änderung als Überarbeitung der Bereitstellung gespeichert, die Sie später entweder auf den vorherigen Zustand zurücksetzen oder die Änderungen aufzeichnen können. Sie können Ihren Verlauf mit kubectl-Rolloutverlauf-Bereitstellung/ einsehen. Mit revisionHistoryLimit können Sie eine Zahl festlegen, die angibt, wie viele Datensätze Sie speichern möchten.

Strategie :Damit können Sie entscheiden, wie Sie mit Aktualisierungen oder horizontaler Pod-Skalierung umgehen möchten. Um den Standardwert RollingUpdate zu überschreiben, müssen Sie den Typschlüssel schreiben, bei dem Sie zwischen zwei Werten wählen können:Recreate oder RollingUpdate.

Die Neuerstellung ist zwar eine schnelle Möglichkeit, Ihre Bereitstellung zu aktualisieren, es werden jedoch alle Pods gelöscht und durch neue ersetzt, aber es bedeutet, dass Sie berücksichtigen müssen, dass es bei dieser Art von Strategie zu einer Systemausfallzeit kommen wird. Das RollingUpdate hingegen ist reibungsloser und langsamer und eignet sich ideal für zustandsbehaftete Anwendungen, die ihre Daten neu ausgleichen können. Das rollingUpdate öffnet die Tür für zwei weitere Felder, nämlich maxSurge und maxUnavailable.

Die erste ist, wie viele Pods über der Gesamtmenge liegen, die Sie beim Durchführen eines Updates benötigen. Beispielsweise wird eine Bereitstellung mit 100 Pods und einem maxSurge von 20 % während der Aktualisierung auf maximal 120 Pods anwachsen. Mit der nächsten Option können Sie auswählen, wie viele Pods in Prozent Sie bereit sind zu töten, um sie in einem 100-Pod-Szenario durch neue zu ersetzen. In Fällen, in denen maximal 20 % nicht verfügbar sind, werden nur 20 Pods gelöscht und durch neue ersetzt, bevor der Rest der Bereitstellung ersetzt wird.

Vorlage :Dies ist nur ein verschachteltes Pod-Spezifikationsfeld, in das Sie alle Spezifikationen und Metadaten der Pods einfügen, die die Bereitstellung verwalten wird.

Wir haben gesehen, dass wir mit Deployments unsere Pods verwalten und sie uns dabei helfen, sie in einem von uns gewünschten Zustand zu halten. Alle diese Pods befinden sich immer noch in einem sogenannten Cluster Netzwerk , bei dem es sich um ein geschlossenes Netzwerk handelt, in dem nur die Kubernetes-Clusterkomponenten miteinander kommunizieren können und sogar über eigene IP-Bereiche verfügen. Wie sprechen wir von außen mit unseren Pods? Wie erreichen wir unsere Bewerbung? Hier kommen Dienste ins Spiel.

Dienste :

Der Name Dienst beschreibt nicht vollständig, was Dienste in Kubernetes tatsächlich tun. Kubernetes-Dienste leiten den Datenverkehr an unsere Pods weiter. Wir können sagen, dass Services das sind, was Pods zusammenhält.

Stellen wir uns vor, wir haben eine typische Frontend/Backend-Anwendung, bei der unsere Frontend-Pods über die IP-Adressen der Pods mit unseren Backend-Pods kommunizieren. Wenn ein Pod im Backend stirbt, verlieren wir die Kommunikation mit unserem Backend. Dies liegt nicht nur daran, dass der neue Pod nicht dieselbe IP-Adresse wie der verstorbene Pod haben wird, sondern wir müssen jetzt auch unsere App neu konfigurieren, um die neue IP-Adresse zu verwenden. Dieses Problem und ähnliche Probleme werden mit Diensten gelöst.

Ein Dienst ist ein logisches Objekt, das den Kube-Proxy anweist, iptables-Regeln basierend darauf zu erstellen, welche Pods sich hinter dem Dienst befinden. Dienste konfigurieren ihre Endpunkte, wie die Pods hinter einem Dienst genannt werden, genauso wie Bereitstellungen wissen, welche Pods gesteuert werden sollen, das Auswahlfeld und die Bezeichnungen der Pods.

Dieses Diagramm zeigt Ihnen, wie Dienste Labels verwenden, um Traffic zu verwalten:

Die Dienste veranlassen nicht nur den Kube-Proxy, Regeln zum Weiterleiten des Datenverkehrs zu erstellen. es wird auch etwas namens kube-dns. auslösen

Kube-dns ist eine Reihe von Pods mit SkyDNS-Containern, die auf dem Cluster ausgeführt werden, der einen DNS-Server und eine Weiterleitung bereitstellt, die Datensätze für Dienste und manchmal Pods zur einfacheren Verwendung erstellen. Immer wenn Sie einen Dienst erstellen, wird ein DNS-Eintrag, der auf die interne Cluster-IP-Adresse des Dienstes verweist, im Format Dienstname.Namespace.svc.cluster.local erstellt. Weitere Informationen zu den DNS-Spezifikationen von Kubernetes finden Sie hier: https://github.com/kubernetes/dns/blob/master/docs/specification.md.

Zurück zu unserem Beispiel:Wir müssen unsere Anwendung jetzt nur noch so konfigurieren, dass sie mit dem vollständig qualifizierten Domainnamen (FQDN) des Dienstes kommuniziert um mit unseren Backend-Pods zu sprechen. Auf diese Weise spielt es keine Rolle, welche IP-Adresse die Pods und Dienste haben. Wenn ein Pod hinter dem Dienst stirbt, kümmert sich der Dienst um alles, indem er den A-Eintrag verwendet, da wir unserem Frontend mitteilen können, dass es den gesamten Datenverkehr an my-svc weiterleiten soll. Die Logik des Dienstes kümmert sich um alles andere.

Es gibt mehrere Arten von Diensten, die Sie erstellen können, wenn Sie das zu erstellende Objekt in Kubernetes deklarieren. Gehen wir sie durch, um zu sehen, welche für die Art von Arbeit, die wir benötigen, am besten geeignet ist:

Cluster-IP :Dies ist der Standarddienst. Wenn Sie einen ClusterIP-Dienst erstellen, wird ein Dienst mit einer Cluster-internen IP-Adresse erstellt, die nur innerhalb des Kubernetes-Clusters geroutet werden kann. Dieser Typ ist ideal für Pods, die nur miteinander kommunizieren müssen und den Cluster nicht verlassen müssen.

NodePort :Wenn Sie diese Art von Dienst erstellen, wird standardmäßig ein zufälliger Port von 30000 bis 32767 zugewiesen, um Datenverkehr an die Endpunkt-Pods des Dienstes weiterzuleiten. Sie können dieses Verhalten überschreiben, indem Sie im Port-Array einen Knotenport angeben. Sobald dies definiert ist, können Sie über : auf Ihre Pods zugreifen. Dies ist nützlich, um von außerhalb des Clusters über die Knoten-IP-Adresse auf Ihre Pods zuzugreifen.

LoadBalancer :Die meiste Zeit werden Sie Kubernetes auf einem Cloud-Anbieter ausführen. Der LoadBalancer-Typ ist für diese Situationen ideal, da Sie Ihrem Dienst über die API Ihres Cloud-Anbieters öffentliche IP-Adressen zuweisen können. Dies ist der ideale Dienst, wenn Sie mit Ihren Pods von außerhalb Ihres Clusters kommunizieren möchten. Mit LoadBalancer können Sie nicht nur eine öffentliche IP-Adresse zuweisen, sondern mithilfe von Azure auch eine private IP-Adresse aus Ihrem virtuellen privaten Netzwerk zuweisen. Sie können also über das Internet oder intern in Ihrem privaten Subnetz mit Ihren Pods sprechen.

Sehen wir uns die YAML-Definition eines Dienstes noch einmal an:

apiVersion:v1kind:Servicemetadata:   name:my-servicespec:selector:       app:front-end type:NodePort ports:   - name:http   port:80   targetPort:8080   nodePort:30024   protocol:TCP

Die YAML-Datei eines Dienstes ist sehr einfach, und die Spezifikationen variieren je nach Art des Dienstes, den Sie erstellen. Aber das Wichtigste, was Sie berücksichtigen müssen, sind die Portdefinitionen. Werfen wir einen Blick auf diese:

  • Port:Dies ist der verfügbar gemachte Service-Port
  • targetPort:Dies ist der Port auf den Pods, an den der Dienst Datenverkehr sendet
  • nodePort:Dies ist der Port, der verfügbar gemacht wird

Obwohl wir jetzt verstehen, wie wir mit den Pods in unserem Cluster kommunizieren können, müssen wir noch verstehen, wie wir das Problem lösen, dass unsere Daten jedes Mal verloren gehen, wenn ein Pod beendet wird. Hier ist Beständig Volumen (PV ) zum Einsatz kommt.

Kubernetes und dauerhafter Speicher

Dauerhafte Speicherung in der Containerwelt ist ein ernstes Problem. Der einzige Speicher, der über Containerläufe hinweg persistent ist, sind die Ebenen des Images, und sie sind schreibgeschützt. Die Schicht, auf der der Container ausgeführt wird, ist lesbar/schreibbar, aber alle Daten in dieser Schicht werden gelöscht, sobald der Container beendet wird. Bei Pods ist dies dasselbe. Wenn ein Container stirbt, sind die darin geschriebenen Daten weg.

Kubernetes verfügt über eine Reihe von Objekten, um die Speicherung über Pods hinweg zu handhaben. Die erste, die wir besprechen werden, sind Bände.

Volumes

Volumes lösen eines der größten Probleme, wenn es um persistente Speicherung geht. Zunächst einmal sind Volumes eigentlich keine Objekte, sondern eine Definition der Spezifikation eines Pods. Wenn Sie einen Pod erstellen, können Sie im Spezifikationsfeld des Pods ein Volume definieren. Container in diesem Pod können das Volume in ihrem Mount-Namespace bereitstellen, und das Volume ist über Container-Neustarts oder -Abstürze hinweg verfügbar. Volumes sind jedoch an die Pods gebunden, und wenn der Pod gelöscht wird, ist auch das Volume verschwunden. Die Daten auf dem Band sind eine andere Geschichte; Datenpersistenz hängt vom Back-End dieses Volumes ab.

Kubernetes unterstützt mehrere Arten von Volumes oder Volume-Quellen und wie sie in den API-Spezifikationen bezeichnet werden, die von Dateisystemzuordnungen vom lokalen Knoten über virtuelle Laufwerke von Cloud-Anbietern bis hin zu softwaredefinierten speichergestützten Volumes reichen. Lokale Dateisystem-Mounts sind die häufigsten, die Sie sehen werden, wenn es um reguläre Volumes geht. Es ist wichtig zu beachten, dass der Nachteil der Verwendung des lokalen Knotendateisystems darin besteht, dass die Daten nicht auf allen Knoten des Clusters verfügbar sind und nur auf dem Knoten, auf dem der Pod geplant war.

Sehen wir uns an, wie ein Pod mit einem Volume in YAML definiert wird:

apiVersion:v1kind:Podmetadata:name:test-pdspec:container:- image:k8s.gcr.io/test-webserver   name:test-container   volumeMounts:   - mountPath:/test-pd     name:test-volume volumes:- name:test-volume   hostPath:     path:/data   type:Directory

Beachten Sie, dass es ein Feld mit dem Namen „volumes“ unter „spec“ und ein weiteres mit dem Namen „volumeMounts“ gibt.

Im ersten Feld (Volumes) definieren Sie das Volume, das Sie für diesen Pod erstellen möchten. Dieses Feld erfordert immer einen Namen und dann eine Volume-Quelle. Je nach Quelle sind die Anforderungen unterschiedlich. In diesem Beispiel wäre die Quelle hostPath, das lokale Dateisystem eines Knotens. hostPath unterstützt mehrere Arten von Zuordnungen, darunter Verzeichnisse, Dateien, Blockgeräte und sogar Unix-Sockets.

Unter dem zweiten Feld, volumeMounts, haben wir mountPath, wo Sie den Pfad innerhalb des Containers definieren, in dem Sie Ihr Volume bereitstellen möchten. Mit dem Namensparameter geben Sie dem Pod an, welches Volume verwendet werden soll. Dies ist wichtig, da Sie unter „Volumes“ mehrere Arten von Volumes definieren können und der Pod nur anhand des Namens erkennen kann, welches.

Weitere Informationen zu den verschiedenen Volume-Typen finden Sie hier https://kubernetes.io/docs/concepts/storage/volumes/#types-of-volumes und im Kubernetes-API-Referenzdokument (https://kubernetes.io/docs /reference/generated/kubernetes-api/v1.11/#volume-v1-core).

Dass Volumes mit den Pods sterben, ist nicht ideal. Wir brauchen dauerhaften Speicher, und so entstand der Bedarf an PVs.

Persistente Volumes, Ansprüche auf persistente Volumes und Speicherklassen

Der Hauptunterschied zwischen Volumes und PVs besteht darin, dass PVs im Gegensatz zu Volumes eigentlich Kubernetes-API-Objekte sind, sodass Sie sie einzeln wie separate Entitäten verwalten können und daher auch nach dem Löschen eines Pods bestehen bleiben.

Sie fragen sich vielleicht, warum dieser Unterabschnitt PV, persistent hat Lautstärke Ansprüche (PVCs ) und Speicherklassen gemischt. Das liegt daran, dass sie alle voneinander abhängen und es wichtig ist, zu verstehen, wie sie miteinander interagieren, um Speicher für unsere Pods bereitzustellen.

Let's begin with PVs and PVCs. Like volumes, PVs have a storage source, so the same mechanism that volumes have applies here. You will either have a software-defined storage cluster providing a logical unit number  (LUN ), a cloud provider giving virtual disks, or even a local filesystem to the Kubernetes node, but here, instead of being called volume sources, they are called persistent volume types  instead.

PVs are pretty much like LUNs in a storage array:you create them, but without a mapping; they are just a bunch of allocated storage waiting to be used. PVCs are like LUN mappings:they are backed or bound to a PV and also are what you actually define, relate, and make available to the pod that it can then use for its containers.

The way you use PVCs on pods is exactly the same as with normal volumes. You have two fields:one to specify which PVC you want to use, and the other one to tell the pod on which container to use that PVC.

The YAML for a PVC API object definition should have the following code:

apiVersion:v1kind:PersistentVolumeClaimmetadata:name:gluster-pvc  spec:accessModes:- ReadWriteMany       resources:    requests:      storage:1Gi   

The YAML for pod should have the following code:

kind:PodapiVersion:v1metadata:name:mypodspec:containers:   - name:myfrontend     image:nginx     volumeMounts:     - mountPath:"/mnt/gluster"       name:volume volumes:   - name:volume     persistentVolumeClaim:       claimName:gluster-pvc

When a Kubernetes administrator creates PVC, there are two ways that this request is satisfied:

  • Static :Several PVs have already been created, and then when a user creates PVC, any available PV that can satisfy the requirements will be bound to that PVC.
  • Dynamic :Some PV types can create PVs based on PVC definitions. When PVC is created, the PV type will dynamically create a PV object and allocate the storage in the backend; this is dynamic provisioning. The catch with dynamic provisioning is that you require a third type of Kubernetes storage object, called a storage class .

Storage classes are like a way of tiering  your storage. You can create a class that provisions slow storage volumes, or another one with hyper-fast SSD drives. However, storage classes are a little bit more complex than just tiering. As we mentioned in the two ways of creating PVC, storage classes are what make dynamic provisioning possible. When working on a cloud environment, you don't want to be manually creating every backend disk for every PV. Storage classes will set up something called a provisioner , which invokes the volume plug-in that's necessary to talk to your cloud provider's API. Every provisioner has its own settings so that it can talk to the specified cloud provider or storage provider.

You can provision storage classes in the following way; this is an example of a storage class using Azure-disk as a disk provisioner:

kind:StorageClassapiVersion:storage.k8s.io/v1metadata:name:my-storage-classprovisioner:kubernetes.io/azure-diskparameters:storageaccounttype:Standard_LRS kind:Shared

Each storage class provisioner and PV type will have different requirements and parameters, as well as volumes, and we have already had a general overview of how they work and what we can use them for. Learning about specific storage classes and PV types will depend on your environment; you can learn more about each one of them by clicking on the following links:

  • https://kubernetes.io/docs/concepts/storage/storage-classes/#provisioner
  • https://kubernetes.io/docs/concepts/storage/persistent-volumes/#types-of-persistent-volumes

In this article, we learned about what Kubernetes is, its components, and what are the advantages of using orchestration are. With this, identifying each of Kubernetes API objects, their purpose and their use cases should be easy. You should now be able to understand how the master nodes control the cluster and the scheduling of the containers in the worker nodes.

If you found this article useful, ‘ Hands-On Linux for Architects ’ should be helpful for you. With this book, you will be covering everything from Linux components and functionalities to hardware and software support, which will help you implementing and tuning effective Linux-based solutions. You will be taken through an overview of Linux design methodology and core concepts of designing a solution. If you’re a Linux system administrator, Linux support engineer, DevOps engineer, Linux consultant or anyone looking to learn or expand their knowledge in architecting, this book is for you.


Linux
  1. Was ist Kubernetes? Vollständiger Leitfaden

  2. So richten Sie einen Kubernetes-Cluster mit Rancher ein

  3. So stellen Sie Redis-Cluster auf Kubernetes bereit

  4. So stellen Sie Ihren ersten Pod in einem Kubernetes-Cluster bereit

  5. Kubernetes-Cluster mit Rancher einrichten

Ein Leitfaden für Systemadministratoren zu grundlegenden Kubernetes-Komponenten

Lernen Sie Kubernetes von Ihrem lokalen Computer aus

Erstellen eines einzelnen Kubernetes-Clusters auf Steuerungsebene mit kubeadm

Kubernetes-Cluster mit K3S mit Multipass von Canonical

Verwendung von Grafana &Prometheus Kubernetes Cluster Monitoring

So installieren Sie Kubernetes-Cluster auf CentOS 8