Persistenter Speicher für Container – Microservices jetzt auch stateful

04.02.2019 / Dr. Stephan Muthmann /

aus Netzwerk-Insider-Ausgabe Februar 2019

Container und ihr Einsatz in der Unternehmens-IT sind derzeit in aller Munde. Die Popularität dieser Technologie stieg sprunghaft an, seit die Firma Docker eine Plattform zum einfachen und intuitiven Ausführen, Verteilen und Entwickeln von Containern veröffentlichte. Darüber hinaus wird z.B. über das immens populäre Kubernetes-Projekt eine Lösung zur automatisierten Orchestrierung von großen Zahlen von Containern bereitgestellt. Auf dieser Basis halten Container vermehrt Einzug in die produktionskritischen Bereiche der Unternehmensrechenzentren.

Der ursprüngliche Gedanke bei der Entwicklung von Containern war, dass sie prinzipiell flüchtig sind. Bei Bedarf werden neue Instanzen gestartet, wenn sie nicht mehr benötigt werden verschwinden sie wieder zusammen mit möglichen Veränderungen in den Daten. Da vermehrt auch Applikationen „containerisiert“ werden, die Zugriff auf persistente Daten benötigen, ist dieser Ansatz nicht mehr ausreichend.

In diesem Artikel stelle ich die wichtigsten Technologien für die Bereitstellung von persistentem Speicher sowohl für einzelne Container als auch in Orchestrierungsplattformen vor.

Der ursprüngliche Gedanke bei der Entwicklung von Containern war, dass sie prinzipiell flüchtig sind. Bei Bedarf werden neue Instanzen gestartet, wenn sie nicht mehr benötigt werden verschwinden sie wieder zusammen mit möglichen Veränderungen in den Daten. Außerdem sollen Container möglichst „schlank“ sein und den Host so wenig wie möglich belasten. Auf diesem Prinzip basiert auch der Aufbau eines Container-Dateisystems. Wie in Abbildung 1 dargestellt, werden Container aus einem Image abgeleitet. Dieses Image, im Bild als Beispiel das Ubuntu 15.04 Image, ist aus verschiedenen Read-Only-Schichten aufgebaut, die während seiner Erzeugung gestapelt wurden.

Ableitung von Containern aus einem Image. Jeder Container verfügt lediglich über eine möglichst dünne beschreibbare Schicht, die zum tatsächlichen Speicherbedarf beiträgt

Abbildung 1: Ableitung von Containern aus einem Image. Jeder Container verfügt lediglich über eine möglichst dünne beschreibbare Schicht, die zum tatsächlichen Speicherbedarf beiträgt

Images können sowohl aus öffentlichen (z.B. Docker Hub) oder privaten (z.B. Red Hat Quay, Google Container Registry) Registries mittels des „Pull“ Befehls bezogen werden. Sie werden lokal auf dem Host gespeichert. Wird ein Container gestartet, leitet Docker ihn aus dem Basis-Image ab. Lediglich eine, möglichst kleine, beschreibbare Schicht wird genutzt um Daten zu verändern. Für einen laufenden Container wird also ausschließlich für diese Schicht auf dem Host Speicherplatz benötigt. Identische Container „teilen“ sich ein Ursprungsimage. Durch diesen Mechanismus kann also eine große Zahl von Containern auf einem Host betrieben werden, ohne viel Speicherplatz zu benötigen – natürlich unter der Voraussetzung, dass ausreichend CPU, GPU (Graphics Processing Unit) und Memory-Ressourcen verfügbar sind. Müssen während des Betriebs eines Containers Daten aus dem Image verändert werden, kopiert der Speichertreiber diese zunächst in die beschreibbare Schicht, ändert sie und speichert sie dort zwischen. Diese Technologie – auch als „Copy on Write“ bezeichnet – sorgt dafür, dass ein Großteil der Daten von Containern, die aus demselben Image abgeleitet werden, nur einmal gespeichert werden müssen. Im Prinzip ähnelt diese Art der Verringerung des benötigten Speicherplatzes also der Deduplizierung in Enterprise-Speichersystemen. Wenn aber z.B. zwei Container, die aus einem Basis-Image abgeleitet wurden, dieselben Daten verändern, werden diese zweimal gespeichert.

Das Stapeln von Dateisystemen mit einer dünnen beschreibbaren Schicht hat zwei entscheidende Nachteile: Zum einen erzeugt die Copy on Write Technologie einen nicht zu vernachlässigenden Overhead: Für jeden Schreibvorgang muss der Speichertreiber zunächst Schicht für Schicht nach der zu ändernden Datei suchen. Anschließend wird diese kopiert und verändert. Noch entscheidender – zumindest aus Sicht dieses Artikels – ist die Tatsache, dass die beschreibbare Schicht beim Stoppen eines Containers wieder verschwindet.

Die einfachste Möglichkeit diese Nachteile zu umgehen, ist das Mounten von lokalen Verzeichnissen innerhalb eines Containers. Wie in Abbildung 2 dargestellt können sowohl mehrere Container auf ein Verzeichnis zugreifen oder Verzeichnisse dediziert bereitgestellt werden.

Mounten von lokalen Volumes in Container

Abbildung 2: Mounten von lokalen Volumes in Container

Im Gegensatz zum in Abbildung 1 dargestellten Modell nimmt die Größe des Containers selbst bei der Veränderung von Dateien nicht zu. Das eingebundene Verzeichnis ist nicht Teil der beschreibbaren Schicht aus der Abbildung.

Für die Einbindung derartiger Verzeichnisse existieren drei verschiedene Varianten:

  • Bind Mounts: Diese nutzen das Dateisystem des Hosts. Bind Mounts sind die am längsten verfügbare Möglichkeit, persistenten Speicher in Containern zu nutzen. Durch die direkte Einbindung in das Dateisystem des Hosts stellen Bind Mounts vergleichsweise hohe Leistungsfähigkeit bereit. Allerdings ist ihre Funktionalität im Vergleich zu Volumes stark eingeschränkt.
  • Volumes: Volumes sind die von Docker bevorzugte Methode für die Nutzung von persistentem Speicher. Sie werden vollständig von Docker verwaltet. Daraus ergeben sich Vorteile wie der stabile Zugriff von mehreren Containern auf ein Verzeichnis oder die Verwaltung mittels der Docker API.
  • tmpfs mounts: Diese Art von Verzeichnis ist nicht für die persistente Speicherung von Daten gedacht. Es wird ein Verzeichnis im Arbeitsspeicher des Hosts angelegt, das nicht Teil der beschreibbaren Schicht aus Abbildung 1 ist. Ein Anwendungsfall ist z.B. die vergleichsweise sichere Speicherung von sensiblen Daten außerhalb der Host-Festplatten. Im Vergleich zu den anderen beiden Varianten haben tmpfs-mounts zwei Einschränkungen: Zum einen sind sie nur innerhalb einer Linux-Umgebung verfügbar. Zum anderen können sie nicht von mehreren Containern gleichzeitig genutzt werden.

In Abbildung 3 sind die unterschiedlichen Varianten miteinander verglichen.

Unterschied zwischen bind mounts, volumes und tmpfs mounts bei Docker.

Abbildung 3: Unterschied zwischen bind mounts, volumes und tmpfs mounts bei Docker.

Docker Volume Plugin

Die bisher diskutierten Möglichkeiten zur Einbindung von persistentem Speicher haben sich lediglich auf die Nutzung der Festplatten von Hosts beschränkt. Obwohl z.B. mittels Volumes zwar die Daten auch auf entfernte Hosts ausgelagert werden können, fehlen Enterprise Features wie Snapshots zur Datensicherung oder Hochverfügbarkeit. Mit den bisher vorgestellten Technologien könnten diese lediglich genutzt werden, wenn die Festplatten der Docker Hosts bzw. die relevanten Verzeichnisse durch SAN-Speicher bereitgestellt werden.

Um die Funktionalität der Docker-Plattform durch externe Dienste zu erweitern, stehen sogenannte „Engine Plugins“ zur Verfügung, die als Images verteilt werden. Aktuell existieren Plugins für die Einbindung von Netzwerkfunktionen, für die Autorisierung und eben für persistenten Speicher als sogenannte „Volume Plugins“. Während für die Netzwerk- und Autorisierungsvarianten jeweils drei unterschiedliche Plugins genutzt werden können, gibt es für die Speicheranbindung über 20 Varianten. Diese reichen von solchen, die von Speicherherstellern entwickelt wurden (z.B. Nimble Storage Volume Plugin, HPE 3Pr Storage Plugin) bis hin zu Plugins der großen Cloud-Provider (z.B. Azure File Storage Plugin). Wie in Abbildung 4 dargestellt, wird das Plugin auf jedem Host der Docker Engine als Container „zur Seite gestellt“.

Nachdem das Plugin installiert ist, wird zunächst ein Volume erzeugt. Geschieht das z.B. in einer VMware vSphere-Umgebung, sowohl für klassischen als auch für vSAN-Speicher, ist lediglich folgender Befehl erforderlich:

docker volume create --driver= vsphere --name=MyVolume -o [optionale Parameter]

Je nach Plugin sind verschiedene Optionen wie Thin Provisioning, Replikation oder Deduplizierung verfügbar.

Anbindung von externem Speicher mit Volume Plugins

Abbildung 4: Anbindung von externem Speicher mit Volume Plugins

Die Einbindung von persistentem Speicher über Volume Plugin ist in Abbildung 5 dargestellt. Das Plugin stellt dem Docker-Daemon Verzeichnisse zur Verfügung, welche per Bind Mount (s.o.) im Container genutzt werden.

Beim Start des Containers wird das Verzeichnis über das –volume Flag im Container eingebunden.

Bewertungskriterien
Als Entscheidungshilfe für die Auswahl eines Plugins werden die Beispiele anhand der folgenden Kriterien miteinander verglichen:

Unterstützte Speicherumgebungen
Welche Speichersysteme können mit dem Plugin genutzt werden? Als Speichersysteme kommen sowohl zentrale Speicherlösungen wie z.B. SAN-Speicher in Frage als auch Software-Lösungen wie verteilte Dateisysteme oder Cloud Speicher. Dieses Kriterium ist relevant, wenn persistenter Speicher aus unterschiedlichen Quellen für Container genutzt werden soll.

Verfügbare Optionen
Kann der persistente Speicher z.B. durch Spiegelung um Hochverfügbarkeit ergänzt oder durch Deduplizierung effizienter genutzt werden? Dieses Kriterium ist relevant, wenn Speicher mit Enterprise-Features zum Einsatz kommen muss. Die verfügbaren Optionen hängen natürlich direkt von den Eigenschaften des Speichers ab.

Einbindung von persistentem Speicher mittels Volume Plugin

Abbildung 5: Einbindung von persistentem Speicher mittels Volume Plugin

Multi-Engine-Nutzung
Kann ein Volume von mehreren Docker Engines (z.B. auf verschiedenen Hosts oder innerhalb mehrerer VMs) gleichzeitig genutzt werden? Können Container z.B. nach einem Ausfall auf einem neuen Host wieder gestartet werden und von dort auf ihr ursprüngliches Volume zugreifen? Dieses Kriterium ist relevant, wenn Container in einem Hochverfügbarkeitscluster genutzt werden oder mehrere Container Teil einer Applikation sind und Zugriff auf dieselben Daten benötigen.

Zertifizierung für die Docker Enterprise Edition
Seit Mitte des Jahres 2018 ist die zweite Version der Docker Enterprise Edition verfügbar. Diese kommt vor allem dann zum Einsatz, wenn produktive Applikationen als Container betrieben werden. Unter anderem können die Hersteller von Plugins diese von Docker zertifizieren lassen. Im Rahmen der Zertifizierung werden die Plugins als Container verteilt. Diese werden u.a. darauf geprüft, ob sie anhand von Best-Practices erstellt wurden. Außerdem wird die API-Compliance getestet und ein Schachstellen-Scan durchgeführt. Dieses Kriterium ist relevant, wenn im Unternehmen die Docker Enterprise Edition zum Einsatz kommt bzw. geplant ist, diese einzusetzen.

Verfügbare Plugins
Wie bereits beschrieben, steht mittlerweile eine große Zahl an Plugins verschiedener Plugins zur Verfügung. Im Folgenden werden einige davon vorgestellt und in ihrer Funktionalität verglichen. Die in der Auflistung enthaltenen Beispiele stehen exemplarisch für OpenSource-Projekte zur Einbindung unterschiedlicher Backends (Rex-Ray), Plugins für die Nutzung von Cloud-Speicher (Cloudstor), Plugins innerhalb einer herstellerspezifischen Virtualisierungsumgebung (VDVS) und eine Speicherhersteller-spezifische Lösung (HPE 3Par Volume Plugin).

Cloudstor
Das Cloudstor-Plugin wurde von Docker selbst für Docker for Azure entwickelt. Primärer Einsatzzweck ist die Bereitstellung von Speicher innerhalb von Microsoft Azure und Amazon Web Services Public Clouds. Werden die dort verfügbaren Container-Dienste genutzt, steht das Cloudstor-Plugin in der Theorie automatisch zur Verfügung. Allerdings ist zu beachten, dass es sich hier um ein sehr neues Feature handelt, das seine Zuverlässigkeit erst noch nachweisen muss. (siehe Tabelle 1)

Cloudstor

Tabelle 1: Cloudstor


REX-Ray Plugin

Tabelle 2: REX-Ray Plugin

REX-Ray Plugin
Haupt-Contibutor zur Entwicklung des REX-Ray Plugins ist der Speicherhersteller DellEMC ({code} by DellEMC). Eigentlich stellt REX-Ray eine Sammlung von verschiedenen Plugins für unterschiedliche Speicherumgebungen dar. So werden z.B. das DellEMC ScaleIO- und das Isilon-Speichersystem unterstützt. Darüber hinaus können u.a. auch Cloud-Speicher (Amazon EBS, EFS und S3FS, Google GCE Persistent Disk) eingebunden werden. (siehe Tabelle 2)

vSphere Docker Volume Service
Über den vSphere Docker Volume Service (VDVS) kann persistenter Speicher, der an eine vSphere-Umgebung angebunden ist, von Containern genutzt werden. Das gilt sowohl für VMware-eigenen Speicher (vSAN) als auch für externen Speicher, der mittels iSCSI oder Fibre Channel per VMFS verfügbar gemacht wird. Außerdem kann NAS-Speicher genutzt werden, der mittels NFS angebunden ist. (siehe Tabelle 3)

vSphere Docker Volume Service

Tabelle 3: vSphere Docker Volume Service


HPE 3Par Volume Plugin

Tabelle 4: HPE 3Par Volume Plugin

HPE 3Par Volume Plugin
Das HPE 3Par Volume Plugin wurde für eine spezielle Familie von Enterprise-Speichersystemen entwickelt. Dementsprechend groß ist das verfügbare Featureset. So können z.B. auch die Replikation zwischen Knoten des Speichersystems oder Quality of Service Parameter in den Optionen des Volume Create Befehls konfiguriert werden. (siehe Tabelle 4)

Fazit
Mittlerweile steht eine große Anzahl von verschiedenen Möglichkeiten zur Einbindung von persistentem Speicher in Container zur Verfügung. Je nachdem, ob eine vorhandene Speicherlösung genutzt werden soll oder z.B. Speicher in der Pu-blic-Cloud genutzt wird, muss das entsprechende Plugin gewählt werden. Damit steht dem Betrieb von Applikationen, die stateful sind, in Containern an dieser Stelle prinzipiell nichts mehr im Wege.

Container-Orchestrierung
Eine der größten Stärken von Containern ist die Möglichkeit zum schnellen Erzeugen und Abschalten von Instanzen. Dies kann z.B. aufgrund von veränderter Last oder auch nach Ausfällen von einzelnen Hosts erforderlich sein. Diese Stärken spielen vor allem dann eine Rolle, wenn Container in produktiven IT-Umgebungen eingesetzt werden. In diesem Umfeld ist die verlässliche Orchestrierung von Containern ein wesentlicher Bestandteil. Sollen Container mit Orchestrierung stateful betrieben werden, spielt die automatisierte Bereitstellung von persistentem Speicher eine entscheidende Rolle.

Bei den Container-Orchestrierungssystemen (CO) hat das ursprünglich von Google entwickelte und mittlerweile unter der Schirmherrschaft der Cloud Native Computing Foundation (CNCF) entwickelte Kubernetes den mit Abstand größten Marktanteil. Dieser verfestigt sich auch durch die Verfügbarkeit von Kubernetes bei den wichtigsten Cloud Anbietern (AWS EKS, Azure AKS oder Google GKE) oder durch die verstärkte Präsenz von VMware, die z.B. durch die Übernahme des Kubernetes-Consulting-Unternehmens heptio deutlich wird. Daher liegt der Fokus der weiteren Betrachtung auf Kubernetes.

Persistenter Speicher in Kubernetes
In Abbildung 6 ist der grundlegende Aufbau eines Kubernetes-Clusters dargestellt. Einzelne Container, die z.B. die Microservices einer Applikation darstellen, sind in sogenannten „Pods“ zusammengefasst. Das „kubelet“ verwaltet die Container innerhalb eines Pods. In den meisten Fällen enthält ein Pod lediglich einen Container, da er z.B. nur über eine IP-Adresse angesprochen wird. Ein Pod beschränkt sich dabei immer auf eine sogenannte „Kubernetes-Node“. Eine solche Node kann entweder aus einem physischen Host oder einer virtuellen Maschine bestehen. Applikationen werden als sogenannte Services an externe Nutzer bereitgestellt. Im Prinzip stellt ein Service einen Cluster aus mehreren äquivalenten Pods dar, die über eine virtuelle IP-Adresse erreicht werden können. Der Zugriff für die Nutzer wird über den „kube-proxy“ verwaltet, der auf jeder Node läuft.
Die Orchestrierung erfolgt durch Dienste, die auf einem Master laufen. Im Prinzip kann jeder Knoten eines Clusters als Master definiert werden. In der Praxis werden dafür meistens dedizierte Hosts genutzt, die redundant aufgebaut werden können. Der Kube-Controller-Manager ist die zentrale Management-Instanz für die Controller eines Clusters. Zu diesen zählen z.B. der Node-Controller, der überwacht, ob einzelne Nodes oder der Replication-Controller verfügbar ist, der die Anzahl der Pods, die für einen Service gefordert sind, steuert. In der etcd-Datenbank werden Informationen zum Status des Clusters vorgehalten, der scheduler verteilt angeforderte Pods auf die vorhandenen Ressourcen. Zentrale Kommunikationsinstanz ist der Kube-apiserver. Dieser nutzt die Kubernetes API, um sowohl die Clusterkomponenten anzusprechen als auch als externe Administrationsschnittstelle z.B. für 3rd-Party-Dienste zu fungieren.

Grundlegender Aufbau eines Kubernetes-Clusters

Abbildung 6: Grundlegender Aufbau eines Kubernetes-Clusters

Persistenter Speicher wird in Kubernetes auf zwei Arten bereitgestellt, die sich eher „organisatorisch“ als technisch unterscheiden:

  • Volumes werden zusammen mit einem Pod erzeugt und existieren nicht eigenständig. D.h. wenn ein Pod gelöscht wird, verschwindet auch das zugehörige Volume.
  • Persistent Volumes werden als eigenständige Instanz, unabhängig von den Pods, erzeugt. Sie werden von einem Pod per „Persistent Volume Claim (PVC)“ angefordert.

Für beide Varianten gilt, dass je Pod eine beliebige Anzahl von Volumes genutzt werden kann. Genau wie für die Volumes im Docker-Kontext gilt auch für Kubernetes, dass mittlerweile eine große Anzahl von Speicheranbietern unterstützt wird. Dazu zählen z.B. AWS EBS, CEPHfs oder vSphere Volumes (= mounten eines VMDK-Files) genauso wie die Einbindung von Speicher, der mittels iSCSI, Fibre Channel oder NFS am Host verfügbar ist. Ein besonderer Typ von Volume – die Nutzung des Container Storage Interfaces – wird weiter unten noch näher behandelt.

Die Einbindung im Container wird letztlich durch das kubelet verwaltet und erfolgt für das Beispiel Docker wie oben beschrieben. Der Speichertyp und das Verzeichnis, in das der Speicher gemountet werden soll, werden im Konfigurationsfile des Pods beschrieben.

Persistent Volumes wiederum können auf zwei verschiedene Arten angefordert werden: Entweder wird das Volume bereits im Vorfeld durch den Administrator bereitgestellt oder der PVC erfolgt dynamisch. In diesem Fall müssen sogenannte „Storage Classes“ definiert werden. In diesen wird z.B. definiert, welches der Volume-Plugins genutzt werden soll, ob das Volume bereits mit Filesystem ausgestattet wird oder auch ob das Volume an eine bestimmte Node gebunden werden soll. Abhängig von den Möglichkeiten des Speichers können außerdem drei verschiedene Zugriffsmethoden definiert werden:

  • ReadWriteOnce: Lesen/Schreiben nur von einer Node
  • ReadOnlyMany: Lesen von mehreren Nodes
  • ReadWriteMany: Lesen und Schreiben von mehreren Nodes

Fazit
Wie am Beispiel von Kubernetes dargestellt, ist persistenter Speicher für Container auch mit Orchestrierungslösungen verfügbar. Der Nutzung von Applikationen, die stateful sind, steht also prinzipiell nichts mehr im Wege. Allerdings bleibt zu beachten, dass einige der oben beschriebenen Features teilweise noch im Alpha- oder Beta-Stadium sind. Geht es also um kritische Anwendungen, sind ausführliche Tests des Gesamtkonstruktes unumgänglich. Außerdem fehlt aktuell noch ein verlässlicher Standard für die Anbindung von externem Speicher. Die vorhandenen Plugins werden zusammen mit Kubernetes entwickelt und in die Kubernetes API integriert. Neue Volume-Plugins müssen also in das Kubernetes Repository eingebunden werden. Daher wird seit kurzem eine standardisierte Schnittstelle entwickelt, welche die Einbindung von beliebigen Storage-Plugins unabhängig von Anpassungen des Kubernetes Codes erlaubt.

Funktionalität des Container Storage Interfaces

Abbildung 7: Funktionalität des Container Storage Interfaces

Container Storage Interface

Hier kommt das Container Storage Interface (CSI) ins Spiel: Es gibt Speicherherstellern die Möglichkeit, ihre Plugins an ein standardisiertes Interface zu binden. Wie in Abbildung 7 dargestellt, wird das CSI unabhängig von der Orchestrierungsplattform entwickelt. Es dient als Schnittstelle zwischen Orchestrierung und Speicherhersteller. Mittlerweile ist das CSI in den wichtigsten Orchestrierungslösungen verfügbar (laut github-Repository aktuell Kubernetes, Mesos und Cloud Foundry). Im Falle von Kubernetes z.B. wird es als sogenanntes „Out of Tree Plugin“ integriert. Die Schnittstelle in den Orchestrator wird unabhängig von dessen Basis entwickelt, die Kommunikation zum Speicher erfolgt mittels des gRPC-Protokolls (ein Open Souce Remote Procedure Call Protokoll).

Das CSI bietet den Speicherherstellern die Möglichkeit, ihr Plugin unabhängig von Orchestrierungsplattform und Release der Orchestrierungslösung zu entwickeln. Seit dem 15. November 2018 steht es in Version 1.0 zur Verfügung. Es bleibt zu hoffen, dass die Speicherhersteller den standardisierten Ansatz mit Nachdruck verfolgen und sich diese Technologie durchsetzen wird. Aktuell gibt es z.B. bereits Unterstützung durch NetApp Trident, REX-Ray oder auch durch AWS EBS. Allerdings ist dabei zu beachten, dass die entsprechenden Plugins teilweise noch als alpha-Versionen gekennzeichnet sind.

Komponenten des Container Storage Interfaces

Abbildung 8: Komponenten des Container Storage Interfaces

Zu den wichtigsten Funktionen, die über das CSI gesteuert werden, zählen: Das Erzeugen und Löschen von Volumes und die Zuordnung zu Pods bzw. die Trennung. Außerdem können, wenn es das Speichersystem zulässt, Snapshots erstellt und die Kapazität von Volumes erweitert werden. Neue Volumes können sowohl leer als auch aus Snapshots erzeugt werden.

Betrachtet man die Einbindung von Speicher über das CSI etwas mehr im Detail (Abbildung 8), können am Beispiel von Kubernetes die folgenden wesentlichen Komponenten unterschieden werden:

  • Das Out of Tree Plugin besteht aus mehreren Containern und wird im Kubernetes-Projekt entwickelt. Hier werden externe Treiber beim kubelet registriert, PVCs (siehe oben) abgefangen und die entsprechende Erzeugung/Löschung im externen Speicher angestoßen. Außerdem wird die Anbindung des Volumes an einen Pod angestoßen.
  • Der CSI Controller wird vom Speicherhersteller entwickelt. Er nutzt einen Identity-Service um Status und Funktionalität des Plugins zu prüfen. Außerdem werden die angeforderten Volumes verwaltet, d.h. z.B. erzeugt, gelöscht, einer Node zugewiesen oder Snapshots erstellt.
  • Der Node Controller sorgt für die Anbindung der Volumes an Pods auf einer Node. Außerdem kann über den Identity-Service der Status der Volumes abgefragt werden.

In den CSI Spezifikationen [1] sind verschiedene Architekturmodelle beschrieben, die sowohl eine Trennung von Master und Node auf unterschiedlichen Hosts als auch „Node-only“ zulassen.

Container Attached Storage

Container Attached Storage

Abbildung 9: Container Attached Storage

Die bisher beschriebenen Ansätze für die Bereitstellung von persistentem Speicher setzen auf die Verwaltung durch den Speicherhersteller. Einen etwas anderen Ansatz geht der Container Attached Storage (CAS). Hier wird das Storage-System sozusagen nativ in Kubernetes integriert. Speicherfunktionalitäten werden von einem Controller, der z.B. als Kubernetes POD ausgelegt ist, orchestriert. Als physischer Speicher können sowohl die Festplatten der Speichersysteme als auch 3rd-Party-Speicher genutzt werden, der in diesem Ansatz allerdings lediglich seine Kapazität bereitstellen muss. Wie in Abbildung 9 dargestellt, wird Speicherplatz mittels Volumes in Storage-PODs verwaltet. Diese Volumes werden an Applikations-PODs weitergegeben.

Enterprise-Storage-Features wie Replikation oder Snapshots werden durch den CAS-Controller gesteuert.

Ein aktuelles Beispiel für diesen Ansatz stellt das OpenSource-Projekt Open-EBS dar. Im Fall von Kubernetes wird das Plugin in der aktuellen Version wie die bereits beschriebenen Volume-Plugins in Kubernetes integriert. In OpenEBS selbst stehen verschiedene Storage-Engines zur Verfügung. Die cStor Engine z.B. basiert auf der Einbindung von Speicherressourcen mittels iSCSI. Das ZFS Dateisystem wird genutzt, um den Speicherplatz zu verwalten.

Vorteil des CAS-Ansatzes ist, dass der Container-Ansatz vollständig auf die Speicherebene erweitert wird. Wird persistenter Speicher benötigt, wird er in Form von Containern mit der bekannten Agilität bereitgestellt. Durch die Bindung von Speicher-PODs an die Applikationscontainer können diese gemeinsam erzeugt und vernichtet werden und auch gemeinsam zwischen Hosts wandern. Die erforderlichen Speichereigenschaften können feingranular an die Anforderungen der Applikationen angepasst werden.

Ohne auf aktuelle Benchmarks zurückgreifen zu können ist allerdings zu erwarten, dass durch den Umweg über einen Speicher-POD ein Performance-Nachteil entsteht.

Lösungen für die Bereitstellung von persistentem Speicher

Tabelle 5: Lösungen für die Bereitstellung von persistentem Speicher

Fazit

In Tabelle 5 sind die verschiedenen Lösungen für die Bereitstellung von persistentem Speicher für Container noch einmal zusammengefasst.

Die Idee, dass auch Container persistenten Speicher benötigen, ist noch vergleichsweise neu. Daher findet aktuell noch sehr viel technologische Entwicklung statt. Insbesondere von den Standardisierungsbemühungen durch das CSI können sowohl die Speicherhersteller als auch Anwender und die Entwickler der Orchestrierungsplattformen profitieren. Es bleibt also zu hoffen, dass an dieser Stelle weitergearbeitet wird.

Verweise

[1] https://github.com/container-storage-interface/spec/blob/master/spec.md

Der Netzwerk Insider gehört mit seinen Produkt- und Markt-Bewertungen rund um IT-Infrastrukturen zu den führenden deutschen Technologie-Magazinen. Der Bezug des Netzwerk Insiders ist kostenlos.

© Copyright - ComConsult