Unsere Erfahrung bei der Entwicklung eines CSI-Treibers in Kubernetes für Yandex.Cloud



Wir freuen uns, Ihnen mitteilen zu können, dass Flant seinen Beitrag zu den Open Source-Tools für Kubernetes durch die Veröffentlichung einer Alpha-Version des CSI-Treibers (Container Storage Interface) für Yandex.Cloud ergänzt.

Bevor wir jedoch zu den Implementierungsdetails übergehen, werden wir die Frage beantworten, warum dies überhaupt erforderlich ist, wenn Yandex bereits über den Managed Service für Kubernetes-Service verfügt .

Einführung


Warum ist das?


In unserem Unternehmen entwickelt sich von Beginn des Betriebs von Kubernetes in der Produktion (d. H. Seit mehreren Jahren) unser eigenes Tool (Deckshaus), das wir übrigens auch bald als Open Source-Projekt zur Verfügung stellen wollen. Mit seiner Hilfe konfigurieren und konfigurieren wir alle unsere Cluster einheitlich. Derzeit gibt es mehr als 100 davon auf den unterschiedlichsten Hardwarekonfigurationen und in allen verfügbaren Cloud-Diensten.

Cluster, die Deckhouse verwenden, verfügen über alle für die Arbeit erforderlichen Komponenten: Balancer, Überwachung mit praktischen Diagrammen, Metriken und Warnungen, Benutzerauthentifizierung durch externe Anbieter für den Zugriff auf alle Dashboards usw. Es macht keinen Sinn, einen solchen "aufgepumpten" Cluster in eine verwaltete Lösung zu integrieren, da dies häufig entweder unmöglich ist oder dazu führt, dass die Hälfte der Komponenten deaktiviert werden muss.

NB : Dies ist unsere Erfahrung und sehr spezifisch. Wir behaupten keinesfalls, dass jeder unabhängig an der Bereitstellung von Kubernetes-Clustern teilnehmen sollte, anstatt vorgefertigte Lösungen zu verwenden. Übrigens haben wir keine wirkliche Erfahrung mit dem Betrieb von Kubernetes von Yandex und werden in diesem Artikel keine Bewertung dieses Dienstes abgeben.

Was ist das und für wen?


Wir haben also bereits über den modernen Speicheransatz in Kubernetes gesprochen: Wie funktioniert CSI und wie kam die Community zu diesem Ansatz ?

Derzeit haben viele große Cloud-Dienstanbieter Treiber für die Verwendung ihrer Cloud-Laufwerke als beständiges Volume in Kubernetes entwickelt. Wenn der Lieferant keinen solchen Treiber hat, aber gleichzeitig alle erforderlichen Funktionen über die API bereitgestellt werden, hindert Sie nichts daran, den Treiber selbst zu implementieren. Und so geschah es mit Yandex.Cloud.

Als Grundlage für die Entwicklung haben wir den CSI-Treiber für die DigitalOcean-Cloud und einige Ideen aus dem Treiber für GCP übernommen , da die Interaktion mit der API dieser Clouds (Google und Yandex) eine Reihe von Ähnlichkeiten aufweist. Insbesondere die API undGCP und Yandex geben ein Objekt zurück Operation, um den Status langwieriger Vorgänge zu verfolgen (z. B. Erstellen einer neuen Festplatte). Für die Interaktion mit der Yandex.Cloud- API wird das Yandex.Cloud Go-SDK verwendet .

Das Ergebnis der geleisteten Arbeit wird auf GitHub veröffentlicht und kann für diejenigen nützlich sein, die aus irgendeinem Grund ihre eigene Installation von Kubernetes auf virtuellen Yandex.Cloud-Maschinen verwenden (jedoch keinen vorgefertigten verwalteten Cluster) und Festplatten über CSI verwenden (bestellen) möchten.

Implementierung


Hauptmerkmale


Derzeit unterstützt der Treiber die folgenden Funktionen:

  • Ordnen von Datenträgern in allen Zonen des Clusters gemäß der Topologie der Knoten im Cluster.
  • Entfernen zuvor bestellter Festplatten;
  • Offline-Größenänderung für Festplatten (Yandex. Cloud unterstützt nicht die Zunahme von Festplatten, die auf einer virtuellen Maschine bereitgestellt werden). Informationen zum Ändern des Treibers, um die Größe so einfach wie möglich zu ändern, finden Sie weiter unten.

In Zukunft ist geplant, Unterstützung für das Erstellen und Entfernen von Snapshot-Datenträgern zu implementieren.

Die Hauptschwierigkeit und ihre Überwindung


Das Fehlen der Möglichkeit, Festplatten in der Yandex.Cloud-API in Echtzeit zu erweitern, ist eine Einschränkung, die den Größenänderungsvorgang für PV (Persistent Volume) erschwert: In diesem Fall muss der Pod der Anwendung, die die Festplatte verwendet, gestoppt werden. Dies kann zu einem einfachen Vorgang führen Anwendungen. Wenn der CSI-Controller

gemäß der CSI-Spezifikation meldet, dass er nur die Größe von Datenträgern "offline" ( VolumeExpansion.OFFLINE) ändern kann , sollte der Vorgang zum Erhöhen des Datenträgers folgendermaßen ablaufen:

Wenn das Plugin nur über VolumeExpansion.OFFLINEErweiterungsmöglichkeiten verfügt und das Volume derzeit auf einem Knoten veröffentlicht oder verfügbar ist, ControllerExpandVolumeMUSS NUR nach einem der folgenden Aufrufe aufgerufen werden:

  • Das Plugin ist Controller- PUBLISH_UNPUBLISH_VOLUMEfähig und ControllerUnpublishVolumewurde erfolgreich aufgerufen.

ODER ABER

  • Das Plugin verfügt NICHT über Controller- PUBLISH_UNPUBLISH_VOLUMEFunktionen, das Plugin über Knotenfunktionen STAGE_UNSTAGE_VOLUMEund NodeUnstageVolumewurde erfolgreich abgeschlossen.

ODER ABER

  • Das Plugin verfügt PUBLISH_UNPUBLISH_VOLUMEweder über Controller- noch über Knotenfunktionen STAGE_UNSTAGE_VOLUMEund NodeUnpublishVolumewurde erfolgreich abgeschlossen.

Im Wesentlichen bedeutet dies, dass die Festplatte vor dem Erhöhen von der virtuellen Maschine getrennt werden muss.

Leider erfüllt die Implementierung der CSI-Spezifikation durch Sidecar diese Anforderungen nicht:

  • Im Beiwagen-Container csi-attacher, der für das Vorhandensein der erforderlichen Lücke zwischen den Halterungen verantwortlich sein sollte, wird diese Funktionalität bei Offline-Größenänderung einfach nicht implementiert. Eine Diskussion darüber wurde hier eingeleitet .
  • Was ist in diesem Zusammenhang ein Beiwagencontainer? Das CSI-Plugin selbst interagiert nicht mit der Kubernetes-API, sondern reagiert nur auf gRPC-Aufrufe, die Sidecar-Container an sie senden. Letztere werden von der Kubernetes-Community entwickelt.

In unserem Fall (CSI-Plugin) ist der Vorgang zum Erhöhen der Festplatte wie folgt:

  1. Wir erhalten einen gRPC-Anruf ControllerExpandVolume.
  2. Wir versuchen, die Festplatte in der API zu vergrößern, erhalten jedoch eine Fehlermeldung über die Unmöglichkeit, den Vorgang auszuführen, da die Festplatte bereitgestellt ist.
  3. Wir speichern die Festplattenkennung in einer Karte, die die Festplatten enthält, für die Sie eine Erhöhungsoperation ausführen müssen. Der Kürze halber werden wir diese Karte als bezeichnen volumeResizeRequired;
  4. Löschen Sie den Pod, der die Festplatte verwendet, manuell. Kubernetes wird es neu starten. Damit der Datenträger ControllerPublishVolumevor Abschluss des Erhöhungsvorgangs beim Mounten keine Zeit zum Mounten ( ) hat, überprüfen wir, ob dieser Datenträger noch vorhanden ist, volumeResizeRequiredund geben einen Fehler zurück.
  5. Der CSI-Treiber versucht, die Größenänderungsoperation erneut auszuführen. Wenn der Vorgang erfolgreich war, löschen Sie die Festplatte von volumeResizeRequired;
  6. weil Die Festplattenkennung fehlt in volumeResizeRequired, sie ControllerPublishVolumeist erfolgreich, die Festplatte ist gemountet, der Pod startet.

Alles sieht einfach aus, aber wie immer gibt es Fallstricke. Extern-Resizer ist an der Festplattenerweiterung beteiligt , die im Falle eines Fehlers während des Vorgangs eine Warteschlange mit einer exponentiellen Verlängerung der Timeout-Zeit von bis zu 1000 Sekunden verwendet:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  // 10 qps, 100 bucket size.  This is only for retry speed and its only the overall factor (not per item)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

Dies kann periodisch dazu führen, dass der Vorgang des Erhöhens der Scheibe um mehr als 15 Minuten gedehnt wird und somit die Unzugänglichkeit des entsprechenden Pods.

Die einzige Möglichkeit, die es uns ermöglichte, die potenziellen Ausfallzeiten ganz einfach und schmerzlos zu reduzieren, war die Verwendung unserer Version des externen Resizers mit einem maximalen Zeitlimit von 5 Sekunden :

workqueue.NewItemExponentialFailureRateLimiter(5*time.Millisecond, 5*time.Second)

Wir hielten es nicht für notwendig, dringend eine Diskussion einzuleiten und einen externen Resizer zu patchen, da Offline-Größenänderungsdatenträger ein Atavismus sind, der bald von allen Cloud-Anbietern verschwinden wird.

Wie fange ich an?


Der Treiber wird in Kubernetes Version 1.15 und höher unterstützt. Damit der Fahrer arbeiten kann, müssen die folgenden Anforderungen erfüllt sein:

  • Das Flag wird --allow-privilegedauf den Wert truefür den API-Server und das Kubelet gesetzt.
  • Enthalten --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truefür API-Server und Kubelet;
  • Propagation Mount ( Mount Propagation ) sollte im Cluster enthalten sein. Bei Verwendung von Docker muss der Dämon so konfiguriert sein, dass gemeinsam genutzte Bereitstellungen zulässig sind.

Alle notwendigen Schritte für die Installation selbst sind in README beschrieben . Bei der Installation werden Objekte in Kubernetes aus Manifesten erstellt.

Damit der Fahrer funktioniert, benötigen Sie Folgendes:

  • Geben Sie die Kennung des Yandex.Cloud-Katalogverzeichnisses ( folder-id) im Manifest an ( siehe Dokumentation ).
  • Für die Interaktion mit der Yandex.Cloud-API im CSI-Treiber wird ein Dienstkonto verwendet. Im geheimen Manifest müssen Sie die autorisierten Schlüssel an das Dienstkonto übergeben. In der Dokumentation wird beschrieben, wie Sie ein Dienstkonto erstellen und die Schlüssel abrufen.

Im Allgemeinen - probieren Sie es aus und wir freuen uns über Feedback und neue Probleme, wenn Sie auf Probleme stoßen!

Weitere Unterstützung


Aus diesem Grund möchten wir darauf hinweisen, dass wir diesen CSI-Treiber nicht aus dem großen Wunsch heraus implementiert haben, Spaß beim Schreiben von Anwendungen auf Go zu haben, sondern aufgrund des dringenden Bedarfs innerhalb des Unternehmens. Es erscheint nicht ratsam, unsere eigene Implementierung zu unterstützen. Wenn Yandex Interesse zeigt und beschließt, den Treiber weiterhin zu unterstützen, werden wir das Repository gerne zur Verfügung stellen.

Darüber hinaus verfügt Yandex im von Kubernetes verwalteten Cluster wahrscheinlich über eine eigene Implementierung des CSI-Treibers, der in Open Source veröffentlicht werden kann. Diese Entwicklungsoption erscheint uns ebenfalls günstig - die Community kann den bewährten Treiber des Dienstanbieters und nicht eines Drittunternehmens verwenden.

PS


Lesen Sie auch in unserem Blog:

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


All Articles