Unsere Erfahrungen bei der Entwicklung des CSI-Treibers in Kubernetes für Yandex.Cloud

Unsere Erfahrungen bei der Entwicklung des CSI-Treibers in Kubernetes für Yandex.Cloud

Wir freuen uns, bekannt zu geben, dass das Unternehmen „Flant“ seinen Beitrag zu Open Source-Tools für Kubernetes mit der Veröffentlichung von der Alpha-Version des CSI-Treibers (Container Storage Interface) für Yandex.Cloud erweitert.

Aber bevor wir zu den Details der Implementierung kommen, beantworten wir die Frage, warum das überhaupt notwendig ist, wo Yandex bereits einen Dienst hat, Managed Service for Kubernetes..

Einführung

Warum das?

Innerhalb unseres Unternehmens entwickelt sich seit Beginn der Produktion (also seit mehreren Jahren) ein eigenes Tool (Deckhouse), das wir übrigens auch bald als Open Source-Projekt verfügbar machen möchten. Damit konfigurieren und verwalten wir unsere Cluster einheitlich, und derzeit haben wir bereits über 100 Cluster, die auf den unterschiedlichsten Hardware-Konfigurationen und in allen verfügbaren Cloud-Diensten laufen.

Cluster, die Deckhouse verwenden, enthalten alle notwendigen Komponenten für den Betrieb: Loadbalancer, Monitoring mit übersichtlichen Grafiken, Metriken und Alerts, sowie die Authentifizierung von Benutzern über externe Anbieter für den Zugang zu allen Dashboards und vieles mehr. Ein derart "aufgerüsteter" Cluster eignet sich nicht für eine verwaltete Lösung, da dies oft entweder unmöglich ist oder dazu führt, dass die Hälfte der Komponenten deaktiviert werden muss.

NB: Das ist unsere Erfahrung, und sie ist ziemlich spezifisch. Wir behaupten keineswegs, dass jeder selbstständig Kubernetes-Cluster aufbauen sollte, anstatt auf vorhandene Lösungen zurückzugreifen. Übrigens haben wir keine praktischen Erfahrungen mit Kubernetes von Yandex und werden in diesem Artikel keine Bewertung dieses Dienstes abgeben.

Was ist das und für wen ist es gedacht?

Wir haben bereits über den modernen Ansatz für Speicher in Kubernetes gesprochen: wie CSI funktioniert und wie die Community zu diesem Ansatz kam. zu solch einem Ansatz.

Derzeit haben viele große Cloud-Anbieter Treiber entwickelt, um ihre "Cloud"-Festplatten als Persistent Volume in Kubernetes zu nutzen. Wenn ein Anbieter jedoch keinen solchen Treiber hat, aber alle erforderlichen Funktionen über eine API bereitstellt, steht nichts im Wege, einen eigenen Treiber zu implementieren. Genau das haben wir mit Yandex.Cloud erreicht.

Als Grundlage für die Entwicklung haben wir den CSI-Treiber für die Cloud von DigitalOcean und ein paar Ideen aus dem Treiber für GCP, da die Interaktion mit den APIs dieser Clouds (Google und Yandex) einige Gemeinsamkeiten aufweist. Insbesondere geben die APIs sowohl von GCPYandex als auch von Yandex Operation ein Objekt zurück, um den Status langwieriger Vorgänge (z. B. die Erstellung einer neuen Festplatte) zu verfolgen. Für die Interaktion mit der API von Yandex.Cloud wird das.

Yandex.Cloud Go SDK verwendet. Das Ergebnis der geleisteten Arbeit

Implementierung

Grundlegende Funktionen

wurde auf GitHub veröffentlicht

  • und könnte nützlich sein für diejenigen, die aus bestimmten Gründen eine eigene Kubernetes-Installation auf virtuellen Maschinen in Yandex.Cloud verwenden (aber keinen fertigen verwalteten Cluster) und Festplatten über CSI nutzen möchten. Aktuell unterstützt der Treiber folgende Funktionen:
  • Löschung zuvor bestellter Festplatten;
  • Offline-Größe für Festplatten (Yandex.Cloud, unterstützt nicht Erhöhung von Festplatten, die mit der virtuellen Maschine verbunden sind). Wie es erforderlich war, den Treiber anzupassen, um das Resize so schmerzlos wie möglich durchzuführen, erfahren Sie unten.

Zukünftig planen wir die Unterstützung für die Erstellung und Löschung von Festplattensnapshots.

Die Hauptschwierigkeit und deren Überwindung

Das Fehlen der Möglichkeit im Yandex.Cloud-API, Festplatten in Echtzeit zu vergrößern – eine Einschränkung, die den Resize-Vorgang für PV (Persistent Volume) erschwert: In diesem Fall muss das Pod der Anwendung, die die Festplatte verwendet, gestoppt werden, was zu einem Ausfall der Anwendung führen kann.

Laut der CSI-Spezifikation, wenn der CSI-Controller angibt, dass er Resize nur „offline“ durchführen kann (VolumeExpansion.OFFLINE), muss der Prozess der Festplattenerweiterung folgendermaßen ablaufen:

Wenn das Plugin nur VolumeExpansion.OFFLINE Erweiterungskapazität hat und das Volume derzeit veröffentlicht oder auf einem Knoten verfügbar ist, dann ControllerExpandVolume muss NUR nachfolgend aufgerufen werden:

  • Das Plugin hat Controller- PUBLISH_UNPUBLISH_VOLUME Fähigkeit und ControllerUnpublishVolume wurde erfolgreich aufgerufen.

ODER

  • Das Plugin hat KEINE Controller- PUBLISH_UNPUBLISH_VOLUME Fähigkeit, das Plugin hat Knoten- STAGE_UNSTAGE_VOLUME Fähigkeit und NodeUnstageVolume wurde erfolgreich abgeschlossen.

ODER

  • Das Plugin hat KEINE Controller- PUBLISH_UNPUBLISH_VOLUME Fähigkeit, noch Knoten STAGE_UNSTAGE_VOLUME Fähigkeit und NodeUnpublishVolume wurde erfolgreich abgeschlossen.

Das bedeutet, dass es notwendig ist, die Festplatte von der virtuellen Maschine zu trennen, bevor Sie sie vergrößern.

Leider ist das eine Umsetzung die CSI-Spezifikationen über Sidecars erfüllen nicht diese Anforderungen:

  • Im Sidecar-Container csi-attacher, der für die Gewährleistung des erforderlichen Abstands zwischen den Montagen verantwortlich sein sollte, wurde die Funktionalität bei einer Offline-Größe einfach nicht implementiert. Diese Diskussion wurde von hier.
  • Was ist überhaupt ein Sidecar-Container in diesem Kontext? Der CSI-Plugin selbst interagiert nicht mit der Kubernetes-API, sondern reagiert lediglich auf die gRPC-Aufrufe, die von den Sidecar-Containern an ihn gesendet werden. Letztere werden von der Kubernetes-Gemeinschaft.

In unserem Fall (CSI-Plugin) sieht die Operation zur Vergrößerung der Festplatte wie folgt aus:

  1. Wir erhalten den gRPC-Aufruf ControllerExpandVolume;
  2. Wir versuchen, die Festplatte über die API zu vergrößern, erhalten jedoch einen Fehler, dass die Operation nicht ausgeführt werden kann, da die Festplatte montiert ist;
  3. Wir speichern die Festplatten-ID in einer Map, die die Festplatten enthält, für die die Vergrößerungsoperation durchgeführt werden muss. Weiterhin werden wir diese Map als volumeResizeRequired;
  4. Manuell entfernen wir das Pod, das die Festplatte verwendet. Kubernetes wird es in der Folge neu starten. Um zu verhindern, dass die Festplatte bereits gemountet wird (ControllerPublishVolume) vor Abschluss der Vergrößerungsoperation beim Mountversuch, überprüfen wir, ob die Festplatte noch in volumeResizeRequired und geben einen Fehler zurück;
  5. Der CSI-Treiber versucht, die Resize-Operation erneut auszuführen. Erfolgt die Operation erfolgreich, entfernen wir die Festplatte aus dem volumeResizeRequired;
  6. Da die Festplatten-ID in volumeResizeRequired, ControllerPublishVolume vorhanden ist, wird die Operation erfolgreich durchgeführt, die Festplatte wird gemountet und das Pod wird gestartet.

Das klingt alles recht einfach, aber wie immer gibt es Haken. Die Vergrößerung der Festplatten wird von der external-resizerübernommen, die im Falle eines Fehlers bei der Durchführung der Operation eine Warteschlange nutzt mit exponentiellem Timeout-Anstieg auf bis zu 1000 Sekunden:

func DefaultControllerRateLimiter() RateLimiter {
  return NewMaxOfRateLimiter(
  NewItemExponentialFailureRateLimiter(5*time.Millisecond, 1000*time.Second),
  // 10 qps, 100 bucket size. Dies ist nur für die Wiederholgeschwindigkeit und ist nur der Gesamtfaktor (nicht pro Element)
  &BucketRateLimiter{Limiter: rate.NewLimiter(rate.Limit(10), 100)},
  )
}

Dies kann gelegentlich dazu führen, dass die Diskvergrößerungsoperation sich über 15 Minuten oder mehr ausdehnt, was zu einer Nichtverfügbarkeit des entsprechenden Pods führt.

Die einzige Möglichkeit, die uns geholfen hat, die potenzielle Ausfallzeit einfach und schmerzfrei zu reduzieren, war die Nutzung unserer eigenen Version des external-resizers mit einer maximalen Zeitüberschreitung. in 5 Sekunden:

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

Wir hielten es nicht für notwendig, sofort eine Diskussion zu beginnen und den external-resizer zu patchen, denn das Offline-Resize von Festplatten ist ein Relikt, das bald bei allen Cloud-Anbietern verschwinden wird.

Wie starte ich?

Der Treiber wird in Kubernetes Version 1.15 und höher unterstützt. Folgende Anforderungen müssen erfüllt sein:

  • Flagge --allow-privileged muss auf true für den API-Server und kubelet gesetzt sein;
  • Die Funktionalitäten --feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=true für den API-Server und kubelet gesetzt sein;
  • Die Montageverbreitung (mount propagation) muss im Cluster aktiviert sein. Bei Verwendung von Docker muss der Daemon so konfiguriert sein, dass shared mounts erlaubt sind.

Alle notwendigen Schritte für die Installation selbst sind im README. Die Installation besteht darin, Objekte in Kubernetes aus Manifests zu erstellen.

Für den Betrieb des Treibers benötigen Sie Folgendes:

  • Geben Sie in das Manifest die Katalog-ID ein (folder-id) von Yandex.Cloud (siehe Dokumentation);
  • Für die Interaktion mit der Yandex.Cloud API wird im CSI-Treiber ein Dienstkonto verwendet. Im Secret-Manifest müssen Sie autorisierte Schlüssel vom Dienstkonto übergeben. In der Dokumentation beschrieben, wie man ein Dienstkonto erstellt und Schlüssel erhält.

Im Großen und Ganzen — probieren Sie es aus., und wir freuen uns über Ihr Feedback sowie neue Issues, falls Sie auf irgendwelche Probleme stoßen!

Weitere Unterstützung

Zusammenfassend möchten wir betonen, dass wir diesen CSI-Treiber nicht aus einer großen Lust auf das Programmieren von Anwendungen in Go entwickelt haben, sondern aus einem dringenden Bedarf innerhalb des Unternehmens. Es erscheint uns nicht sinnvoll, unsere eigene Implementierung zu unterstützen, daher werden wir, wenn Yandex Interesse zeigt und die Unterstützung des Treibers fortsetzen möchte, das Repository gerne in deren Hände übergeben.

Darüber hinaus hat Yandex wahrscheinlich eine eigene Implementierung des CSI-Treibers im verwalteten Kubernetes-Cluster, die als Open Source veröffentlicht werden könnte. Eine solche Entwicklungsrichtung erscheint uns ebenfalls vorteilhaft – die Community könnte den bewährten Treiber des Dienstanbieters nutzen, anstatt von einem Drittanbieter.

P.S.

Lesen Sie auch in unserem Blog:

Quelle: habr.com

Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server 🔥 Kaufen Sie zuverlässiges Hosting für Websites mit DDoS-Schutz, VPS VDS-Server | ProHoster