Kubernetes Storage Volume Plugins: Flexvolume zu CSI



In den Tagen, als Kubernetes noch v1.0.0 war, gab es Volume-Plugins. Sie wurden benötigt, um eine Verbindung zu Kubernetes-Systemen herzustellen und persistente (permanente) Containerdaten zu speichern. Ihre Anzahl war gering, und unter den ersten gab es Speicheranbieter wie GCE PD, Ceph, AWS EBS und andere.

Plug-Ins wurden zusammen mit Kubernetes geliefert, für die sie ihren Namen erhielten - in-tree. Viele der vorhandenen Plug-Ins reichten jedoch nicht aus. Die Handwerker fügten mithilfe von Patches einfache Plugins zum Kern von Kubernetes hinzu. Danach bauten sie ihre eigenen Kubernetes und stellten sie auf ihre Server. Im Laufe der Zeit stellten die Entwickler von Kubernetes jedoch fest, dass der Fisch nicht gelöst werden konnte. Die Leute brauchen eine Angelrute . Und in Kubernetes v1.2.0 erschien es ...

Flexvolume Plugin: minimale Angelrute


Die Entwickler von Kubernetes haben das FlexVolume-Plugin erstellt, eine logische Bindung von Variablen und Methoden für die Arbeit mit Flexvolume-Treibern von Drittanbietern.

Lassen Sie uns einen Blick auf den FlexVolume-Treiber werfen. Dies ist eine bestimmte ausführbare Datei (Binärdatei, Python-Skript, Bash-Skript usw.), die bei ihrer Ausführung Befehlszeilenargumente verwendet und eine Nachricht mit zuvor bekannten Feldern im JSON-Format zurückgibt. Konventionell ist das erste Befehlszeilenargument immer die Methode, und die restlichen Argumente sind ihre Parameter.


CIFS teilt das Verbindungsschema in OpenShift. Flexvolume-Treiber - direkt in der Mitte

Die Mindestanzahl von Methoden sieht folgendermaßen aus:

flexvolume_driver mount #      pod' #   : { "status": "Success"/"Failure"/"Not supported", "message": "       ", } flexvolume_driver unmount #      pod' #   : { "status": "Success"/"Failure"/"Not supported", "message": "       ", } flexvolume_driver init #     #   : { "status": "Success"/"Failure"/"Not supported", "message": "       ", // ,     attach/deatach "capabilities":{"attach": True/False} } 

Die Verwendung der Methoden zum attach und Trennen bestimmt das Szenario, nach dem Kubelet in Zukunft beim Aufruf des Treibers agieren wird. Es gibt auch spezielle expandvolume und expandfs , die für die dynamische Größenänderung eines Volumes verantwortlich sind.

Als Beispiel für die Änderungen, die die expandvolume Methode expandvolume , und damit die Möglichkeit, die Größenänderung von Volumes in Echtzeit durchzuführen, können Sie unsere Pull-Anforderung im Rook Ceph-Operator überprüfen.

Hier ist eine Beispielimplementierung des Flexvolume-Treibers für die Arbeit mit NFS:

 usage() { err "Invalid usage. Usage: " err "\t$0 init" err "\t$0 mount <mount dir> <json params>" err "\t$0 unmount <mount dir>" exit 1 } err() { echo -ne $* 1>&2 } log() { echo -ne $* >&1 } ismounted() { MOUNT=`findmnt -n ${MNTPATH} 2>/dev/null | cut -d' ' -f1` if [ "${MOUNT}" == "${MNTPATH}" ]; then echo "1" else echo "0" fi } domount() { MNTPATH=$1 NFS_SERVER=$(echo $2 | jq -r '.server') SHARE=$(echo $2 | jq -r '.share') if [ $(ismounted) -eq 1 ] ; then log '{"status": "Success"}' exit 0 fi mkdir -p ${MNTPATH} &> /dev/null mount -t nfs ${NFS_SERVER}:/${SHARE} ${MNTPATH} &> /dev/null if [ $? -ne 0 ]; then err "{ \"status\": \"Failure\", \"message\": \"Failed to mount ${NFS_SERVER}:${SHARE} at ${MNTPATH}\"}" exit 1 fi log '{"status": "Success"}' exit 0 } unmount() { MNTPATH=$1 if [ $(ismounted) -eq 0 ] ; then log '{"status": "Success"}' exit 0 fi umount ${MNTPATH} &> /dev/null if [ $? -ne 0 ]; then err "{ \"status\": \"Failed\", \"message\": \"Failed to unmount volume at ${MNTPATH}\"}" exit 1 fi log '{"status": "Success"}' exit 0 } op=$1 if [ "$op" = "init" ]; then log '{"status": "Success", "capabilities": {"attach": false}}' exit 0 fi if [ $# -lt 2 ]; then usage fi shift case "$op" in mount) domount $* ;; unmount) unmount $* ;; *) log '{"status": "Not supported"}' exit 0 esac exit 1 

Nachdem Sie die eigentliche ausführbare Datei vorbereitet haben, müssen Sie den Treiber im Kubernetes-Cluster auslegen . Der Treiber muss sich auf jedem Knoten des Clusters gemäß einem vordefinierten Pfad befinden. Standardmäßig wurde ausgewählt:

/usr/libexec/kubernetes/kubelet-plugins/volume/exec/__~_/

... aber bei Verwendung verschiedener Kubernetes-Distributionen (OpenShift, Rancher ...) kann der Pfad unterschiedlich sein.

Flexvolume-Probleme: Wie wirft man eine Angelrute?


Das Platzieren des Flexvolume-Treibers auf den Clusterknoten erwies sich als nicht triviale Aufgabe. Nachdem der Vorgang einmal manuell ausgeführt wurde, kann es leicht zu einer Situation kommen, in der neue Knoten im Cluster angezeigt werden: durch Hinzufügen eines neuen Knotens, automatische horizontale Skalierung oder, schlimmer noch, Ersetzen des Knotens aufgrund einer Fehlfunktion. In diesem Fall ist es unmöglich, mit dem Speicher auf diesen Knoten zu arbeiten, bis Sie ihnen den Flexvolume-Treiber auf dieselbe Weise manuell hinzufügen.

Die Lösung für dieses Problem war eines der DaemonSet von Kubernetes - DaemonSet . Wenn ein neuer Knoten im Cluster angezeigt wird, erhält er automatisch einen Pod von unserem DaemonSet, an den ein lokales Volume angehängt ist, um Flexvolume-Treiber zu finden. Nach erfolgreicher Erstellung kopiert pod die erforderlichen Dateien, damit der Treiber auf der Festplatte arbeiten kann.

Hier ist ein Beispiel für ein solches DaemonSet zum Layout des Flexvolume-Plugins:

 apiVersion: extensions/v1beta1 kind: DaemonSet metadata: name: flex-set spec: template: metadata: name: flex-deploy labels: app: flex-deploy spec: containers: - image: <deployment_image> name: flex-deploy securityContext: privileged: true volumeMounts: - mountPath: /flexmnt name: flexvolume-mount volumes: - name: flexvolume-mount hostPath: path: <host_driver_directory> 

... und ein Beispiel für ein Bash-Skript zum Erstellen eines Flexvolume-Treibers:

 #!/bin/sh set -o errexit set -o pipefail VENDOR=k8s.io DRIVER=nfs driver_dir=$VENDOR${VENDOR:+"~"}${DRIVER} if [ ! -d "/flexmnt/$driver_dir" ]; then mkdir "/flexmnt/$driver_dir" fi cp "/$DRIVER" "/flexmnt/$driver_dir/.$DRIVER" mv -f "/flexmnt/$driver_dir/.$DRIVER" "/flexmnt/$driver_dir/$DRIVER" while : ; do sleep 3600 done 

Es ist wichtig, nicht zu vergessen, dass der Kopiervorgang nicht atomar ist . Es ist sehr wahrscheinlich, dass Kubelet den Treiber verwendet, bevor der Vorbereitungsprozess abgeschlossen ist, was zu einem Fehler im System führt. Der richtige Ansatz wäre, zuerst die Treiberdateien unter einem anderen Namen zu kopieren und dann die atomare Umbenennungsoperation zu verwenden.


Schema der Arbeit mit Ceph in der Rook-Anweisung: Der Flexvolume-Treiber im Diagramm befindet sich im Rook-Agenten

Das nächste Problem bei der Verwendung von Flexvolume-Treibern besteht darin, dass für die meisten Speicher die dafür erforderliche Software auf dem Clusterknoten installiert werden sollte (z. B. das ceph-common-Paket für Ceph). Ursprünglich war das Flexvolume-Plugin nicht für die Implementierung derart komplexer Systeme konzipiert.

Eine originelle Lösung für dieses Problem ist die Implementierung des Flexvolume-Treibers des Rook-Operators:

Der Treiber selbst ist als RPC-Client konzipiert. Der IPC-Socket für die Kommunikation befindet sich im selben Verzeichnis wie der Treiber. Wir erinnern uns, dass es zum Kopieren von Treiberdateien gut wäre, DaemonSet zu verwenden, das ein Verzeichnis mit dem Treiber als Volume verbindet. Nach dem Kopieren der erforderlichen Rook-Treiberdateien stirbt dieser Pod nicht ab, sondern stellt über das angeschlossene Volume eine Verbindung zum IPC-Socket als vollwertiger RPC-Server her. Das ceph-common-Paket ist bereits im Pod-Container installiert. Der IPC-Socket gibt die Sicherheit, dass kubelet mit dem bestimmten Pod auf demselben Knoten kommuniziert. Alles Geniale ist einfach! ..

Auf Wiedersehen, unsere liebevollen ... In-Tree-Plugins!


Kubernetes-Entwickler haben festgestellt, dass die Anzahl der Speicher-Plugins im Kernel zwanzig beträgt. Und die Änderung in jedem von ihnen durchläuft irgendwie den gesamten Kubernetes-Veröffentlichungszyklus.

Es stellt sich heraus, dass Sie den gesamten Cluster aktualisieren müssen, um die neue Version des Plugins für die Speicherung zu verwenden . Darüber hinaus werden Sie überrascht sein, dass die neue Version von Kubernetes plötzlich nicht mehr mit dem verwendeten Linux-Kernel kompatibel ist. Daher wischen Sie die Tränen weg und beißen die Zähne zusammen und koordinieren mit den Behörden und Benutzern die Zeit für die Aktualisierung des Linux-Kernels und des Kubernetes-Clusters. Mit möglichen Ausfallzeiten bei der Erbringung von Dienstleistungen.

Die Situation ist mehr als komisch, oder? Der gesamten Community wurde klar, dass der Ansatz nicht funktioniert hat. Mit einer willensstarken Entscheidung kündigen Kubernetes-Entwickler an, dass neue Speicher-Plugins nicht mehr in den Kernel aufgenommen werden. Wie wir bereits wissen, wurden bei der Implementierung des Flexvolume-Plugins eine Reihe von Mängeln aufgedeckt ...

Ein für alle Mal wurde das zuletzt hinzugefügte Plugin für Volumes in Kubernetes, CSI, aufgefordert, das Problem mit persistenten Data Warehouses zu schließen. Die Alpha-Version, die allgemein als Out-of-Tree-CSI-Volume-Plugins bezeichnet wird, wurde in Kubernetes 1.9 angekündigt.

Container Storage Interface oder CSI 3000 drehen!


Zunächst möchte ich darauf hinweisen, dass CSI nicht nur ein Volume-Plugin ist, sondern ein echter Standard für die Erstellung benutzerdefinierter Komponenten für die Arbeit mit Data Warehouses . Es wurde angenommen, dass Container-Orchestrierungssysteme wie Kubernetes und Mesos „lernen“ sollten, wie man mit Komponenten arbeitet, die gemäß diesem Standard implementiert sind. Und jetzt hat Kubernetes schon gelernt.

Was ist das Gerät des CSI-Plugins in Kubernetes? Das CSI-Plugin funktioniert mit speziellen Treibern ( CSI-Treibern ), die von Drittentwicklern geschrieben wurden. Der CSI-Treiber in Kubernetes sollte mindestens aus zwei Komponenten (Pods) bestehen:

  • Controller - verwaltet externen persistenten Speicher. Es ist als gRPC-Server implementiert, für den das StatefulSet Grundelement verwendet wird.
  • Knoten - ist für das Mounten persistenter Speicher auf Clusterknoten verantwortlich. Es ist auch als gRPC-Server implementiert, aber das DaemonSet wird dafür verwendet.


Kubernetes CSI Plugin Workflow

Weitere Einzelheiten zu CSI finden Sie beispielsweise im Artikel „ Grundlegendes zum CSI “, dessen Übersetzung wir vor einem Jahr veröffentlicht haben.

Die Vorteile einer solchen Implementierung


  • Für grundlegende Dinge - zum Beispiel um einen Treiber für einen Knoten zu registrieren - haben Kubernetes-Entwickler eine Reihe von Containern implementiert. Sie müssen keine JSON-Antwort mit Funktionen mehr selbst erstellen, wie dies für das Flexvolume-Plugin getan wurde.
  • Anstatt die Knoten ausführbarer Dateien zu „verschieben“, legen wir jetzt Pods im Cluster an. Dies haben wir ursprünglich von Kubernetes erwartet: Alle Prozesse finden in Containern statt, die mit Kubernetes-Grundelementen bereitgestellt werden.
  • Um komplexe Treiber zu implementieren, müssen Sie keinen RPC-Server und keinen RPC-Client mehr entwickeln. Der Client für uns wurde von Kubernetes-Entwicklern implementiert.
  • Das Übergeben von Argumenten für die Arbeit mit dem gRPC-Protokoll ist viel bequemer, flexibler und zuverlässiger als das Übergeben von Argumenten über Befehlszeilenargumente. Um zu verstehen, wie Sie CSI durch Hinzufügen einer standardisierten gRPC-Methode Unterstützung für Volume-Nutzungsmetriken hinzufügen können, lesen Sie unsere Pull-Anfrage für den vsphere-csi-Treiber.
  • Die Kommunikation erfolgt über IPC-Sockets, um nicht zu verwirren, ob der Kubelet-Pod eine Anfrage gesendet hat oder nicht.

Erinnert Sie diese Liste an irgendetwas? Die Vorteile von CSI sind die Lösung genau der Probleme , die bei der Entwicklung des Flexvolume-Plugins nicht berücksichtigt wurden.

Schlussfolgerungen


CSI als Standard für die Implementierung benutzerdefinierter Plugins für die Interaktion mit Data Warehouses wurde von der Community sehr gut angenommen. Aufgrund seiner Vorteile und Vielseitigkeit werden CSI-Treiber auch für Repositorys wie Ceph oder AWS EBS erstellt, Plugins für die Arbeit, die in der allerersten Version von Kubernetes hinzugefügt wurden.

Anfang 2019 waren In-Tree-Plugins veraltet . Es ist geplant, das Flexvolume-Plugin weiterhin zu unterstützen, es werden jedoch keine neuen Funktionen dafür entwickelt.

Wir selbst haben bereits Erfahrung mit ceph-csi, vsphere-csi und sind bereit, diese Liste zu ergänzen! Bisher bewältigt CSI die ihm zugewiesenen Aufgaben mit einem Knall, und dort warten wir ab.

Vergessen Sie nicht, dass alles Neue gut überdacht ist!

PS


Lesen Sie auch in unserem Blog:

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


All Articles