
Wir freuen uns, bekannt zu geben, dass das Unternehmen „Flant“ seinen Beitrag zu Open Source-Tools für Kubernetes mit der Veröffentlichung von (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, .
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: und 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 und ein paar Ideen aus , da die Interaktion mit den APIs dieser Clouds (Google und Yandex) einige Gemeinsamkeiten aufweist. Insbesondere geben die APIs sowohl von Yandex Yandex Operation ein Objekt zurück, .
Yandex.Cloud Go SDK 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, 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 , 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.OFFLINEErweiterungskapazität hat und das Volume derzeit veröffentlicht oder auf einem Knoten verfügbar ist, dannControllerExpandVolumemuss NUR nachfolgend aufgerufen werden:
- Das Plugin hat Controller-
PUBLISH_UNPUBLISH_VOLUMEFähigkeit undControllerUnpublishVolumewurde erfolgreich aufgerufen.ODER
- Das Plugin hat KEINE Controller-
PUBLISH_UNPUBLISH_VOLUMEFähigkeit, das Plugin hat Knoten-STAGE_UNSTAGE_VOLUMEFähigkeit undNodeUnstageVolumewurde erfolgreich abgeschlossen.ODER
- Das Plugin hat KEINE Controller-
PUBLISH_UNPUBLISH_VOLUMEFähigkeit, noch KnotenSTAGE_UNSTAGE_VOLUMEFähigkeit undNodeUnpublishVolumewurde 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 . - 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 von der Kubernetes-Gemeinschaft.
In unserem Fall (CSI-Plugin) sieht die Operation zur Vergrößerung der Festplatte wie folgt aus:
- Wir erhalten den gRPC-Aufruf
ControllerExpandVolume; - 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;
- 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; - 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 involumeResizeRequiredund geben einen Fehler zurück; - Der CSI-Treiber versucht, die Resize-Operation erneut auszuführen. Erfolgt die Operation erfolgreich, entfernen wir die Festplatte aus dem
volumeResizeRequired; - Da die Festplatten-ID in
volumeResizeRequired,ControllerPublishVolumevorhanden 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 übernommen, die im Falle eines Fehlers bei der Durchführung der Operation 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. :
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-privilegedmuss auftruefür den API-Server und kubelet gesetzt sein; - Die Funktionalitäten
--feature-gates=VolumeSnapshotDataSource=true,KubeletPluginsWatcher=true,CSINodeInfo=true,CSIDriverRegistry=truefür den API-Server und kubelet gesetzt sein; - Die Montageverbreitung () 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 . 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 (); - Für die Interaktion mit der Yandex.Cloud API wird im CSI-Treiber ein Dienstkonto verwendet. Im Secret-Manifest müssen Sie vom Dienstkonto übergeben. In der Dokumentation , wie man ein Dienstkonto erstellt und Schlüssel erhält.
Im Großen und Ganzen — , und wir freuen uns über Ihr Feedback sowie , 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
