
Kubernetes wird zum De-facto-Standard für die Ausführung zustandsloser Anwendungen. Hauptsächlich, weil dadurch die Markteinführungszeit für die Bereitstellung neuer Funktionen erheblich verkürzt werden kann. Das Starten von Stateful-Anwendungen - Datenbanken, Stateful-Microservices - ist immer noch eine schwierige Aufgabe, aber die Notwendigkeit, dem Wettbewerb standzuhalten und eine hohe Bereitstellungsrate aufrechtzuerhalten, zwingt Unternehmen dazu, in diesem Bereich zu experimentieren, und schafft eine Nachfrage nach solchen Lösungen.
Wir präsentieren Ihnen unsere Lösung zum Starten von Stateful Clustern.
Tarantool Cartridge :
Tarantool Kubernetes Operator , für Details frage ich unter cat.
Inhaltsverzeichnis:
- Anstelle von tausend Wörtern
- Was macht der Bediener überhaupt?
- Ein wenig über die Nuancen
- Wie der Bediener arbeitet
- Was der Operator erweitert
- Zusammenfassung
Tarantool ist eine OpenSource-Datenbank und ein Anwendungsserver in einem Paket. Als Datenbank weist sie eine Reihe einzigartiger Merkmale auf: hohe Eisenausnutzungseffizienz, flexibles Datenschema, Unterstützung für In-Memory- und Festplattenspeicher sowie die Möglichkeit der Erweiterung durch die Verwendung der Lua-Sprache. Als Anwendungsserver können Sie den Anwendungscode so nah wie möglich an die Daten verschieben und gleichzeitig eine minimale Antwortzeit und einen maximalen Durchsatz erzielen. Darüber hinaus verfügt Tarantool über
ein umfangreiches Ökosystem , das vorgefertigte Module zur Lösung von Anwendungsproblemen bereitstellt:
Sharding ,
Warteschlange , Module für die einfache Entwicklung (
Cartridge ,
Luatest ), Lösungen für den Betrieb (
Metrics ,
Ansible ) - dies sind nur einige Beispiele.
Trotz aller Vorteile sind die Funktionen einer einzelnen Tarantool-Instanz nicht unbegrenzt: Um Terabytes an Daten zu speichern und Millionen von Anforderungen zu verarbeiten, müssen Sie Dutzende und Hunderte von Instanzen auslösen, und dies ist ein verteiltes System mit all seinen inhärenten Problemen. Um sie zu lösen, haben wir
Tarantool Cartridge , ein Framework, dessen Hauptaufgabe es ist, alle möglichen Schwierigkeiten beim Schreiben verteilter Anwendungen zu verbergen und Entwicklern die Möglichkeit zu geben, sich auf den geschäftlichen Wert der Anwendung zu konzentrieren. Cartridge bietet eine Reihe leistungsstarker Komponenten für die automatische Cluster-Orchestrierung, die automatische Datenverteilung, das Webui für den Betrieb und Entwicklertools.
Tarantool ist nicht nur Technologie, sondern auch ein Team von Ingenieuren, die sich mit der Entwicklung schlüsselfertiger Unternehmenssysteme, Box-Lösungen und dem Support für Open Source-Komponenten befassen.
Weltweit lassen sich unsere Aufgaben in zwei Bereiche unterteilen: die Entwicklung neuer Systeme und die Erweiterung bestehender Lösungen. Zum Beispiel gibt es eine große Basis von einem berühmten Anbieter. Um es für das Lesen zu skalieren, haben sie einen endlich konsistenten Cache auf Tarantool dahinter gelegt. Oder umgekehrt: Um die Aufzeichnung zu skalieren, wird Tarantool in die Hot / Cold-Konfiguration versetzt, in der die Daten beim „Abkühlen“ in den Kühlspeicher und parallel zur Analysewarteschlange gestellt werden. Oder um ein vorhandenes System zu sichern, wird eine Light-Version dieses Systems (Funktionsreserve) geschrieben, die das Haupt-Hot mit Datenreplikation vom Hauptsystem reserviert. Weitere Informationen finden Sie in den
Berichten von T + 2019 .
Alle diese Systeme haben eines gemeinsam: Sie sind recht schwierig zu bedienen. Stellen Sie schnell einen Cluster mit mehr als 100 Instanzen mit Redundanz in 3 Rechenzentren bereit, aktualisieren Sie die Anwendung, in der Daten ohne Ausfallzeiten und Wartungsprobleme gespeichert sind, führen Sie eine Sicherungswiederherstellung im Falle einer Katastrophe oder von Menschen verursachter Fehler durch, stellen Sie ein unauffälliges Komponenten-Failover sicher, organisieren Sie das Konfigurationsmanagement ... Im Allgemeinen eine Tonne interessant.
Und es wäre großartig, wenn all dies noch so einfach betrieben würde, wie es entwickelt wird. Kubernetes macht es möglich, das gewünschte Ergebnis zu erzielen, aber die Verwendung eines spezialisierten Bedieners macht das Leben noch einfacher.
Anstelle von tausend Wörtern
Wir haben ein kleines Beispiel basierend auf Tarantool Cartridge vorbereitet und werden damit arbeiten. Eine einfache Anwendung wie "Distributed Key Value Storage mit HTTP-Schnittstelle". Nach dem Start erhalten wir dieses Bild:

Wo:
- Router - der Teil des Clusters, der für das Akzeptieren und Verarbeiten eingehender HTTP-Anforderungen verantwortlich ist;
- Speichern ist der Teil des Clusters, der für das Speichern und Verarbeiten von Daten verantwortlich ist. 3 Shards steigen aus der Box auf, jeder Master und jedes Replikat.
Um den eingehenden HTTP-Verkehr auf Routern auszugleichen, wird der Kubernetian Ingress verwendet. Daten werden mithilfe
der vshard-Komponente im Speicher auf Tarantool-Ebene
verteilt .
Wir brauchen Kubernetes 1.14+, Minikube wird
funktionieren . Auch die Verfügbarkeit von
Kubectl wird nicht schaden. Um den Operator zu starten, müssen Sie ein ServiceAccount, eine Rolle und eine Rollenbindung dafür erstellen:
$ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/service_account.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/role.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/role_binding.yaml
Tarantool Operator erweitert die Kubernetes-API mit ihren Ressourcendefinitionen. Wir werden sie erstellen:
$ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_cluster_crd.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_role_crd.yaml $ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/crds/tarantool_v1alpha1_replicasettemplate_crd.yaml
Alles ist bereit, um den Operator zu starten. Los geht's:
$ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/deploy/operator.yaml
Wir warten auf den Start des Bedieners und können mit dem Starten der Anwendung fortfahren:
$ kubectl create -f https://raw.githubusercontent.com/tarantool/tarantool-operator/0.0.1/examples/kv/deployment.yaml
In der yaml-Datei mit dem Beispiel wird Ingress auf der Web-Benutzeroberfläche deklariert. Es ist unter
cluster_ip/admin/cluster
verfügbar. Wenn mindestens ein Pod von Ingress aktiv ist, können Sie dort beobachten, wie neue Instanzen zum Cluster hinzugefügt werden und wie sich seine Topologie ändert.
Wir warten auf die Verwendung des Clusters:
$ kubectl describe clusters.tarantool.io examples-kv-cluster
Wir erwarten, dass im Status des Clusters Folgendes angezeigt wird:
… Status: State: Ready …
Alles, die Anwendung ist gebrauchsfertig!
Benötigen Sie mehr Speicherplatz? Shards hinzufügen:
$ kubectl scale roles.tarantool.io storage --replicas=3
Scherben können die Last nicht bewältigen? Erhöhen Sie die Anzahl der Instanzen im Shard, indem Sie die Replikatsatzvorlage bearbeiten:
$ kubectl edit replicasettemplates.tarantool.io storage-template
.spec.replicas
Sie
.spec.replicas
, z. B. 2, um die Anzahl der Instanzen in jedem Replikat auf zwei zu erhöhen.
Ein Cluster wird nicht mehr benötigt? Wir löschen es zusammen mit allen Ressourcen:
$ kubectl delete clusters.tarantool.io examples-kv-cluster
Ist etwas schief gelaufen?
Erzielen Sie das Ticket , wir werden es schnell zerlegen. :) :)
Was macht der Bediener überhaupt?
Beim Start und Betrieb des Tarantool Cartridge-Clusters werden bestimmte Aktionen in einer bestimmten Reihenfolge zu einem bestimmten Zeitpunkt ausgeführt.
Der Cluster selbst wird hauptsächlich über die Admin-API verwaltet: GraphQL über HTTP. Sie können natürlich eine Stufe tiefer gehen und Befehle direkt in die Konsole eingeben, aber dies kommt selten vor. So startet der Cluster beispielsweise:
- Wir erhöhen die erforderliche Anzahl von Tarantool-Instanzen, beispielsweise unter systemd.
- Instanzen zur Mitgliedschaft zusammenführen:
mutation { probe_instance: probe_server(uri: "storage:3301") }
- Weisen Sie Instanzen Rollen zu, schreiben Sie Instanz- und Replikatsatzkennungen vor. Hierfür wird auch die GraphQL-API verwendet:
mutation { join_server( uri:"storage:3301", instance_uuid: "cccccccc-cccc-4000-b000-000000000001", replicaset_uuid: "cccccccc-0000-4000-b000-000000000000", roles: ["storage"], timeout: 5 ) }
- Wir führen einen Bootstrap der Komponente durch, die für das Sharding verantwortlich ist. Auch über die API:
mutation { bootstrap_vshard cluster { failover(enabled:true) } }
Einfach, oder?
Alles wird interessanter, wenn es um die Erweiterung eines Clusters geht. Die Rolle der Router aus dem Beispiel lässt sich einfach skalieren: Erhöhen Sie mehr Instanzen, schließen Sie sie an einen vorhandenen Cluster an - fertig! Die Rolle der Speicher ist etwas schwieriger. Der Speicher ist gespalten. Wenn Sie also Instanzen hinzufügen oder entfernen, müssen Sie die Daten neu ausgleichen, um zu neuen Instanzen zu wechseln / um von gelöschten Instanzen zu wechseln. Wenn dies nicht getan wird, erhalten wir in einem Fall unterlastete Instanzen, im zweiten Fall verlieren wir Daten. Und wenn nicht nur ein, sondern ein Dutzend solcher Cluster mit unterschiedlichen Topologien in Betrieb sind?
Im Allgemeinen ist Tarantool Operator mit all dem beschäftigt. Der Benutzer beschreibt den gewünschten Status des Tarantool Cartridge-Clusters, und der Bediener übersetzt dies in eine Reihe von Aktionen für k8s-Ressourcen und in bestimmte Aufrufe der Tarantool-Cluster-Administrator-API in einer bestimmten Reihenfolge zu einem bestimmten Zeitpunkt und versucht im Allgemeinen, alle Nuancen vor dem Benutzer zu verbergen.
Ein wenig über die Nuancen
Bei der Arbeit mit der Admin-Cluster-API von Tarantool Cartridge ist sowohl die Reihenfolge der Aufrufe als auch deren Herkunft wichtig. Warum so?
Tarantool Cartridge enthält sein Topologie-Repository, seine Service Discovery-Komponente und seine Konfigurationskomponente. Jede Instanz des Clusters speichert eine Kopie der Topologie und Konfiguration in einer Yaml-Datei.
servers: d8a9ce19-a880-5757-9ae0-6a0959525842: uri: storage-2-0.examples-kv-cluster:3301 replicaset_uuid: 8cf044f2-cae0-519b-8d08-00a2f1173fcb 497762e2-02a1-583e-8f51-5610375ebae9: uri: storage-0-0.examples-kv-cluster:3301 replicaset_uuid: 05e42b64-fa81-59e6-beb2-95d84c22a435 … vshard: bucket_count: 30000 ...
Die Aktualisierung erfolgt gemeinsam mit dem
Zwei-Phasen-Festschreibungsmechanismus . Für ein erfolgreiches Upgrade ist ein Quorum von 100% erforderlich: Jede Instanz muss antworten, andernfalls wird ein Rollback durchgeführt. Was bedeutet das für den Betrieb? Alle Anforderungen an die Admin-API, die den Status des Clusters ändern, können am zuverlässigsten an eine Instanz, an den Leader, gesendet werden. Andernfalls besteht die Gefahr, dass auf verschiedenen Instanzen unterschiedliche Konfigurationen auftreten. Tarantool Cartridge weiß nicht, wie man eine Führungswahl durchführt (weiß aber nicht wie), und Tarantool Operator kann - und Sie können dies nur als unterhaltsame Tatsache wissen, weil der Operator alles ruinieren wird.
Außerdem muss jede Instanz eine feste Identität haben, d. H. Eine Menge von
instance_uuid
und
replicaset_uuid
sowie
advertise_uri
. Wenn der Speicher plötzlich neu gestartet wird und sich einer dieser Parameter ändert, besteht die Gefahr, dass das Quorum verletzt wird - der Bediener tut dies auch.
Wie der Bediener arbeitet
Die Aufgabe des Bedieners besteht darin, das System in den vom Benutzer festgelegten Zustand zu bringen und das System in diesem Zustand zu halten, bis neue Anweisungen empfangen werden. Damit der Bediener seine Arbeit ausführen kann, benötigt er:
- Beschreibung des Systemstatus.
- Der Code, der das System in diesen Zustand versetzt.
- Ein Mechanismus zum Integrieren dieses Codes in k8s (zum Beispiel zum Empfangen von Benachrichtigungen über Statusänderungen).
Der Tarantool Cartridge-Cluster wird in k8s durch eine
benutzerdefinierte Ressourcendefinition (CRD) beschrieben . Der Bediener benötigt drei solcher benutzerdefinierten Ressourcen, die unter der Gruppe tarantool.io/v1alpha zusammengefasst sind:
- Cluster ist eine Ressource der obersten Ebene, die einem Tarantool Cartridge-Cluster entspricht.
- Rolle - In Bezug auf Tarantool Cartridge ist dies eine Benutzerrolle .
- ReplicasetTemplate - eine Vorlage, mit der StatefulSets erstellt werden (warum stateful - ich werde es Ihnen etwas später sagen; nicht zu verwechseln mit k8s ReplicaSet).
Alle diese Ressourcen spiegeln direkt das Tarantool Cartridge-Cluster-Beschreibungsmodell wider. Mit einem gemeinsamen Wörterbuch ist es für einen Bediener einfacher, mit Entwicklern zu kommunizieren und zu verstehen, was sie im Produkt sehen möchten.
Der Code, der das System in den angegebenen Zustand bringt - in Bezug auf k8s ist dies Controller. Im Fall des Tarantool-Operators gibt es mehrere Controller:
- ClusterController - ist für die Interaktion mit dem Tarantool Cartridge-Cluster verantwortlich, verbindet Instanzen mit dem Cluster und trennt Instanzen vom Cluster.
- RoleController ist ein Benutzerrollen-Controller, der für die Bereitstellung von StatefulSets aus einer Vorlage und die Verwaltung der Nummer in einer bestimmten Nummer verantwortlich ist.
Wie ist ein Controller? Ein Satz von Code, der die Welt um Sie herum allmählich in Ordnung bringt. ClusterController kann wie folgt schematisch dargestellt werden:

Ein Einstiegspunkt ist eine Überprüfung, ob eine Clusterressource vorhanden ist, für die das Ereignis aufgetreten ist. Existiert nicht? Wir gehen. Gibt es Wir fahren mit dem nächsten Block fort: Übernehmen Sie die Eigentümerschaft über Benutzerrollen. Erfasst eins - links, auf dem zweiten Kreis erfassen wir den zweiten. Und so weiter, bis wir alles erfassen. Werden alle Rollen erfasst? Fahren Sie also mit dem nächsten Operationsblock fort. Und so, bis wir zum letzten kommen; dann können wir annehmen, dass sich das gesteuerte System in einem bestimmten Zustand befindet.
Im Allgemeinen ist alles einfach. Es ist wichtig, die Erfolgskriterien für das Bestehen jeder Stufe zu bestimmen. Zum Beispiel betrachten wir den Vorgang des Beitritts zu einem Cluster als erfolgreich, nicht wenn er bedingten Erfolg = true zurückgibt, sondern wenn er einen Fehler wie "bereits verbunden" zurückgibt.
Und der letzte Teil dieses Mechanismus ist die Integration des Controllers in k8s. In der Luftaufnahme besteht der gesamte k8 aus einer Reihe von Controllern, die Ereignisse generieren und darauf reagieren. Ereignisse durchlaufen Warteschlangen, die wir abonnieren können. Schematisch kann dies wie folgt dargestellt werden:

Der Benutzer ruft
kubectl create -f tarantool_cluster.yaml
, die entsprechende
kubectl create -f tarantool_cluster.yaml
wird erstellt. ClusterController wird über die Erstellung einer Clusterressource benachrichtigt. Und das erste, was er versucht, ist, alle Rollenressourcen zu finden, die Teil dieses Clusters sein sollten. Wenn dies der Fall ist, wird Cluster als Eigentümer für die Rolle zugewiesen und die Rollenressource aktualisiert. Der RoleController erhält eine Benachrichtigung über die Rollenaktualisierung, erkennt, dass die Ressource einen Eigentümer hat, und beginnt mit der Erstellung von StatefulSets. Und so weiter im Kreis: der erste Strigger des zweiten, der zweite Strigger des dritten - und so weiter, bis jemand anhält. Sie können beispielsweise auch alle 5 Sekunden pünktlich auslösen, was manchmal nützlich ist.
Das ist der ganze Operator: Erstellen Sie eine benutzerdefinierte Ressource und schreiben Sie Code, der auf Ereignisse auf Ressourcen reagiert.
Was der Operator erweitert
Bedieneraktionen führen letztendlich dazu, dass k8s Pods und Container erstellen. In dem auf k8s bereitgestellten Tarantool Cartridge-Cluster werden alle Pods zu StatefulSets zusammengeführt.
Warum StatefulSet? Wie ich bereits geschrieben habe, behält jede Tarantool-Cluster-Instanz eine Kopie der Topologie und Konfiguration des Clusters bei, und häufig auf dem App-Server no, no, und sie verwenden eine Art Speicherplatz, z. B. wiederum oder Referenzdaten, und dies ist bereits ein vollständiger Status . Und StatefulSet garantiert auch die Beibehaltung von Identitäts-Pods, was beim Clustering von Instanzen in einem Cluster wichtig ist: Die Identität von Instanzen muss behoben werden, da sonst das Quorum beim Neustart verloren gehen kann.
Wenn alle Clusterressourcen erstellt und in den gewünschten Status versetzt werden, bilden sie die folgende Hierarchie:

Die Pfeile geben die inhaberabhängige Beziehung zwischen Ressourcen an. Es ist notwendig, dass der
Garbage Collector nach uns
aufräumt, wenn beispielsweise der Cluster entfernt wird.
Zusätzlich zu StatefulSets erstellt der Tarantool-Operator den Headless-Dienst, der für die Wahl des Leiters benötigt wird, und über diesen kommunizieren die Instanzen miteinander.
Unter der Haube des Tarantool-Operators verbirgt sich das
Operator Framework , der Operatorcode selbst ist in Golang, hier nichts Außergewöhnliches.
Zusammenfassung
Das ist alles im Allgemeinen! Wir warten auf Feedback und Tickets von Ihnen - ohne sie ist die Alpha-Version alle gleich. Was weiter? Und dann gibt es eine Menge Arbeit, um dies alles in Erinnerung zu rufen:
- Einheit, E2E-Test;
- Chaos Affentest
- Stresstests;
- sichern / wiederherstellen;
- externer Topologieanbieter.
Jedes dieser Themen ist für sich genommen umfangreich und verdient ein eigenes Material. Warten Sie auf Aktualisierungen!