Persistenter Speicher und Container galten bisher nicht unbedingt als Traumpaar, denn Kubernetes & Co. zeigen sich unflexibel, wenn es darum geht, Daten dauerhaft zu speichern. Rook bietet Cloud Native Storage für Kubernetes und will so für Harmonie sorgen.
Ein Bonmot macht dieser Tage auf IT-Konferenzen die Runde: Internetanbieter betreiben die Server, auf deren Basis ihre Kunden serverless werden können. Der Scherz hat einen wahren Kern: Zwar streben Kunden mit ihren Setups einerseits immer stärker in die Cloud und wollen mit dem Betrieb klassischer IT-Infrastruktur immer weniger zu tun haben. Auf Luft und Liebe läuft andererseits aber keine Software.
So sehen sich die Anbieter von IT-Infrastruktur heute Herausforderungen gegenüber, die sich von denen früherer Jahre kaum unterscheiden. Das gilt auch und besonders für das Thema persistente Daten. Klar: Die modernen Architekturansätze auf Basis von Microservices setzen verstärkt auf dynamischen Umgang mit Daten, Fragmentierung, Clustermechanismen und nicht zuletzt auch inhärente Redundanz.
Das alles ändert allerdings nichts daran, dass in jedem Setup irgendwann der Punkt kommt, an dem Daten irgendwo sicher abzulegen sind. Etwa dann, wenn Kundendaten ins Spiel kommen und der Ausfall eines einzelnen Servers nicht dazu führen soll, dass der jeweilige Container samt Kundendaten für immer im Nirwana verschwindet.
Cloudumgebungen wie Open Stack [1] gehen das Problem klassisch an. Sie liefern Komponenten mit, die als Vermittler zwischen dem physischen Speicher auf der einen Seite und den virtuellen Umgebungen auf der anderen fungieren. Meist sind die virtuellen Umgebungen typische VMs und persistenter Storage lässt sich einigermaßen trivial anbinden.
Geht es hingegen um Container, ist die Gemengelage eine andere: Kubernetes ([2], Abbildung 1), Docker [3] und die in reicher Anzahl vorhandenen Alternativen haben zwar alle irgendwie eine Lösung für das persistente Speichern von Daten – so richtig zum Cloud-Native-Konzept passen sie aber alle nicht.

Abbildung 1: Kubernetes ist der unangefochtene Klassenprimus in Sachen Container-Orchestrierung. Mit persistenten, redundanten Volumes tut sich die Lösung aber schwer.
Hier kommt Rook [4] ins Spiel: Es verspricht nicht weniger als Cloud Native Storage für persistente Daten im Kontext von Kubernetes. Die Idee ist einfach: Der Admin kombiniert Rook am besten mit dem Objektspeicher Ceph [5], das ist auch die aktuell empfohlene Variante. Sobald Rook in Kubernetes läuft, steht ein kompletter virtueller Ceph-Cluster zur Verfügung. Über die durch Kubernetes anbindbaren Volumes bekommt dieses seine Datensilos, die es danach wie üblich verwaltet.
Der Clou: Rook integriert sich perfekt in Kubernetes, sodass es sich etwa zentral per API steuern lässt. Dem Kunden steht in seinem Kubernetes-Cluster danach eine neue Art von Volumes zur Verfügung, die sich wie jede andere Volume-Art in Kubernetes nutzen lässt.
Der mit Rook geschaffene Speicher ist aber in alle Kubernetes-Abläufe integriert und kein angeklebtes Anhängsel, wie es bei klassischen Volumes und Containern der Fall ist. De facto verspricht Rook dem Admin also, ein Problem von großer Tragweite schnell und unkompliziert zu lösen – Grund genug, dem genauer auf den Zahn zu fühlen.
Cloud Native
Bevor es allerdings konkret um Rook geht, ist ein kleiner Ausflug ins Cloud-Marketing nötig. Denn was mit Cloud Native Storage eigentlich gemeint sein soll, erschließt sich nur jenen, die sich ohnehin mit der Materie beschäftigen und Rook vermutlich bereits auf dem Schirm haben. Zur Erinnerung: Als Cloud-Native-Applikationen bezeichnet man im Allgemeinen Anwendungen eines neuen Typs, die von vornherein für den Betrieb in der Cloud ausgelegt sind. Bekanntlich stellt die Cloud an die in ihr laufenden Apps andere Anforderungen als konventionelle Setups. Cloudinstallationen gehen etwa davon aus, dass die Anwendungen sich selbst um ihre Redundanz kümmern, statt auf Hilfskonstrukte wie Cluster-Manager zu setzen.
Dabei hilft auch, dass Cloud Native fast immer auf dem Konzept einer Mikroarchitektur fußt: Wo man früher einen riesigen Klumpen Programm entwickelte, schreibt man heute lieber etliche kleine, autarke, aber dafür sehr flotte Komponenten, die am Ende ein stimmiges Gesamtbild ergeben. Erfüllt eine Applikation eben diese Anforderungen, so hält man sie im Allgemeinen für Cloud Native.
Container sind ein äußerst beliebtes Werkzeug beim Bau solcher Programme. Denn sie kommen ohne den riesigen Overhead virtueller Maschinen aus, sind also besonders leichtfüßig und ressourcensparend. Obendrein lassen sie sich durch Werkzeuge wie Kubernetes ganz hervorragend orchestrieren – auch das ein Faktor, der bei Cloud-Native-Applikationen eine große Rolle spielt.
Nicht so einfach
Das alles hat mit Storage mehr zu tun, als man auf den ersten Blick denkt. Denn mit dem Thema persistentes Speichern beschäftigen sich die Cloud-Orchestrierer wie Kubernetes nur sehr ungern. Aus Sicht der Containerumgebung ist die Sache eigentlich auch klar: Wenn die Applikation persistenten Speicher braucht, soll sie sich darum gefälligst selbst kümmern. Etwa so, wie MySQL und Galera das im Gespann tun: Der gesamte Datensatz ist stets in mehreren Instanzen vorhanden. Versagt eine davon, lässt sich sofort einfach eine neue starten, die nach einer kurzen Weile wieder synchron mit ihren Clusterpartnern ist.
Wer als Admin aber schon mal das Vergnügen hatte, sich mit Galera in einem ausgewachsenen Produktivsetup zu befassen, der weiß, dass das nicht so leicht ist, sondern im Gegenteil sehr kompliziert – auf administrativer Ebene wie auch auf Ebene der Entwicklung. Weshalb sich die Entwickler von Cloud-nativen Apps oft genug weigern, sich mit dem Thema überhaupt einmal auseinanderzusetzen und stattdessen mit dem Finger lieber auf die Containerumgebung zeigen.
Wenn allerdings weder die Containerumgebung noch die Applikation das Thema angehen, steht am Ende der Admin im Regen. Er muss sich dann Gedanken machen, wie er persistenten Speicher trotzdem möglich macht. Dabei sind in den vergangenen Jahren manche Krückenkonstruktionen entstanden, die Replikationslösungen an Kubernetes anbauen, die redundanten persistenten Speicher irgendwie ermöglichen. Das Gelbe vom Ei ist das aber nicht.
Rook schafft Abhilfe
An dieser Stelle setzt Rook an. Den Rook-Entwicklern ist nämlich ein entscheidender Punkt aufgefallen: Die Software, die nötig ist, um persistenten Speicher in Cloudumgebungen zu ermöglichen, existiert bereits in Gestalt von Ceph. Nicht umsonst hat Red Hat sich den Ceph-Erfinder Sage Weil samt seiner Firma Inktank vor Jahren für viel Geld einverleibt. Nicht versehentlich ist Ceph aus heutiger Sicht der De-facto-Standard geworden, wenn Software Defined Storage zum Einsatz kommt, um in Clouds skalierbaren Speicher anzubieten. Und auch nicht aus Versehen betreiben einige der größten Clouds der Welt ihren persistenten Speicher mit Ceph.
Besonders positiv: Ceph basiert ausschließlich auf Softwarefunktionen. Zwar benötigt es Blockspeicher als eine Art Datensilo, aber die gesamte Intelligenz, die sich um die Skalierbarkeit und die interne Redundanz kümmert, steckt in Softwarekomponenten. Ceph ist es dabei herzlich egal, ob das, was es als persistenten Speicher untergeschoben bekommt, eine echte Festplatte ist oder etwa ein virtuelles Volume, das an einen Container gehängt ist. Solange Ceph seine Nutzdaten irgendwo ablegen kann, ist aus seiner Sicht die Welt in Ordnung.
Das fehlende Bindeglied
Überspitzt ist also die Aussage durchaus zulässig, dass die Ceph-Entwickler die klassischen Probleme von redundantem, persistierendem Speicher für die Entwickler von Cloud-Native-Applikationen bereits gelöst haben. Bisher fehlte aber eine Möglichkeit, Ceph in Containerumgebungen effektiv zu managen.
Aus Nutzersicht ist es nicht sonderlich attraktiv, sich Container von Hand aufzuziehen, in denen ein Ceph-Cluster läuft. Denn diese VMs wären in die Abläufe der Containerumgebung nicht integriert und ließen sich auch nicht per zentralem API steuern. Obendrein würden sie die Komplexität des Setups auf der administrativen Ebene massiv vergrößern.
Aus Anbietersicht stellt sich das Thema kaum besser dar: Zwar könnte der Anbieter im Hintergrund einen Ceph-Cluster mit entsprechender Konfiguration betreiben, den die Kunden dann nutzen dürfen. Er müsste aber eine brauchbare Integration von Container und Storage bieten. Für Docker existiert zwar ein Ceph-Volume-Treiber, doch der ist weder sonderlich gut gepflegt noch herausragend funktional.
Rook tritt also an, das Bindeglied zwischen Containern und Orchestrierung auf der einen Seite und den Cloud-Native-Applikationen auf der anderen Seite zu sein. Wie funktioniert das in der Praxis?
Simpler Start
Grundvoraussetzung, um Rook auszuprobieren, ist ein schon laufender Kubernetes-Cluster. An den stellt Rook keine besonders hohen Anforderungen. Die Konfiguration sollte nur so gestaltet sein, dass es möglich ist, auf den einzelnen Knoten des Clusters lokale Volumes über den ohnehin vorhandenen Kubernetes-Volume-Manager anzulegen. Falls das nicht auf allen Maschinen der Fall ist, lässt sich in den Pod-Definitionen von Rook explizit festlegen, welche Maschinen der Lösung Storage in Beschlag nehmen dürfen und welche nicht.
Um es den eigenen Nutzern möglichst leicht zu machen, haben sich die Rook- Entwickler einiges einfallen lassen: Rook selbst kommt in Form von Kubernetes-Pods daher, für die sich in Rook entsprechende Beispiele [6] finden. Der Admin startet also auf Basis dieser Dateien die entsprechenden Pods. Zwei Teile von Rook sind dafür unbedingt nötig: Der Namespace namens »operator« enthält alle Komponenten, die für das Steuern von Ceph durch Rook notwendig sind. Der Namespace »cluster« wiederum startet jene Pods, die die Ceph-Komponenten selbst betreiben.
Zur Erinnerung: Damit ein Ceph-Cluster funktioniert, braucht er mindestens die Monitoring-Server (MONs) sowie seine Datensilos, die Object Storage Daemons oder auch OSDs. Die Monitoring-Server kümmern sich in Ceph sowohl um das Erzwingen eines Quorums als auch darum, dass eventuelle Clients wissen, wie sie den Cluster erreichen können. Dazu pflegen sie zwei zentrale Listen: Die MON-Map verzeichnet alle existierenden Monitoring-Server, die OSD-Map die verfügbaren Speichergeräte.
Die MONs fungieren allerdings nicht als eine Art Proxy-Server: Clients müssen zwar zwangsläufig mit einem MON beim ersten Verbinden mit einem Ceph-Cluster sprechen, sobald sie jedoch eine lokale Kopie der MON-Map und der OSD-Map haben, reden sie einerseits direkt mit den OSDs und andererseits auch mit anderen MON-Servern.
Das von Rook gesteuerte Ceph macht von diesen Regeln keine Ausnahmen. Entsprechend startet der Cluster-Namespace aus dem Rook-Beispiel dann auch entsprechende Pods, die als MONs sowie als OSDs fungieren. Ruft der Admin nach dem Start der Namespaces den Befehl »kubectl get pods -n rook« auf, sieht er das sofort: Dann laufen nämlich mindestens drei Pods mit MON-Servern sowie diverse Pods mit OSDs. Hinzu gesellt sich der »rook-api«-Pod, der für Rook selbst von elementarer Bedeutung ist: Er wickelt die Kommunikation mit den anderen Kubernetes-APIs ab.
Das Ende vom Lied: In Kubernetes steht im Anschluss an den Rook-Rollout ein neuer Volume-Typ zur Verfügung, der auf die verschiedenen Ceph-Frontends zeigt und den Nutzer in ihren Pod-Definitionen wie jeden anderen Volume-Typ auch verwenden können.
Komplizierte Technik
Rook wickelt im Hintergrund deutlich mehr Arbeit ab, als der Admin im ersten Augenblick meint. Ein gutes Beispiel dafür ist die Integration in das Kubernetes-Volumes-System. Denn ein in Kubernetes laufendes Ceph ist zwar toll, aber nutzlos, wenn die anderen Pods die dort entstehenden Volumes nicht auch nutzen können. Die Rook-Entwickler sind dem Problem zu Leibe gerückt und haben einen eigenen Volume-Treiber für die Anwendung auf den Zielsystemen geschrieben, der sich an die Kubernetes-Flexvolume-Richtlinien hält.
Hinzu gesellt sich noch ein Rook-Agent, der auf jedem Kubelet-Knoten läuft und dort die Kommunikation mit dem Ceph-Cluster abwickelt. Soll also an einen Pod auf einem Zielsystem ein aus Ceph stammendes Rados Block Device (RBD) angebunden werden, stellt der Agent durch den Aufruf entsprechender Befehle auf jenem System sicher, dass das Volume am Ende auch dem Zielcontainer zur Verfügung steht.
Klotzen statt Kleckern
Ceph unterstützt gegenwärtig drei Zugriffsarten. Die häufigste Variante ist es, Ceph-Block-Geräte zu exponieren, die sich anschließend per »rbd«-Kernelmodul im lokalen System einbinden lassen. Hinzu gesellt sich das Ceph Object Gateway oder auch Rados Gateway (Abbildung 2), das eine Schnittstelle zu Ceph auf Basis der Restful-Protokolle Swift sowie S3 ermöglicht. Und seit einigen Monaten ist endlich auch Ceph-FS für den produktiven Einsatz zugelassen, jenes Frontend also, das ein verteiltes, Posix-kompatibles Dateisystem mit Ceph als Backend-Storage bietet.

Abbildung 2: Das Rados Gateway erlaubt S3-basierten Zugriff auf Ceph, und neben Ceph-FS und RBD beherrscht Rook auch diese Zugriffsmethode.
Aus Admin-Sicht wäre es vermutlich bereits sehr hilfreich gewesen, könnte Rook nur eines der drei Frontends adäquat nutzen, nämlich das für Blockgeräte. Die Rook-Entwickler wollten allerdings nicht kleckern, sondern klotzen und integrierten in ihr Projekt Unterstützung für alle drei Frontends.
Will ein Container also persistenten Speicher aus Ceph nutzen, kann er wahlweise per Volume-Direktive ein echtes Docker-Volume erstellen, sich alternativ für Restful-Zugriffe Zugangsdaten für das Rados Gateway organisieren oder das von Ceph verfügbar gemachte Ceph-FS lokal einbinden. Der Funktionsumfang von Rook ist dabei durchaus beeindruckend.
Steuerung durch Kubernetes
Als Cloud-Native-Storage bezeichnet Rook sich vor allem deshalb, weil es mit dem bereits erwähnten API daherkommt, das sich als Kubernetes-Dienst den laufenden Containern zu erkennen gibt. Anders als bei handgeklöppelten Setups, bei denen der Admin das Ceph seinen Containern an Kubernetes vorbei unterschiebt, stehen den Containern bei der Verwendung von Rook alle Features von Kubernetes im Hinblick auf Volumes zur Verfügung. Fordert ein Container etwa ein Blockgerät an, sieht dies im Container aus wie ein ganz normales Volume, im Hintergrund zeigt es aber auf Ceph.
Die Konfiguration des laufenden Ceph-Clusters ändert Rook bei Bedarf automatisch und ohne dass der Admin oder ein laufender Container irgendwas tun müssten. Will der Admin dagegen eine spezifische Konfiguration hinterlegen, ist das ebenfalls möglich, und zwar direkt über das Rook-API.
Das bietet Vor- und Nachteile. Die Entwickler weisen ausdrücklich darauf hin, dass eines ihrer Ziele darin bestand, den Administrator möglichst fern vom laufenden Ceph-Cluster zu halten. De facto bietet Ceph eine große Zahl von Konfigurationsmöglichkeiten, die Rook schlicht nicht abbildet (Abbildung 3), die sich also auch nicht per Rook-API steuern lassen.

Abbildung 3: Ceph bietet schier unendlich viele Tuning-Möglichkeiten wie etwa hier in »ceph.conf« – Rook abstrahiert diese aber nicht allesamt.
Dafür ist das Verändern der Crush-Map ein gutes Beispiel. Crush steht für Controlled Replication Under Scalable Hashing und bezeichnet den Algorithmus, den Ceph nutzt, um Daten von Clients auf existierende OSDs zu verteilen. Wie die MON-Map und die OSD-Map handelt es sich letztlich also um eine interne Datenbank, die der Admin durchaus modifizieren kann.
Das ist praktisch, wenn er Platten unterschiedlicher Größen im Setup hat oder Daten in einem Cluster auf mehrere Brandschutzzonen verteilen möchte. Rook bildet die Manipulation der Crush-Map allerdings gar nicht erst ab, entsprechende API-Aufrufe fehlen also.
Rook kümmert sich völlig automatisch darum, dass die Nutzer von Problemen im Hintergrund so wenig mitbekommen wie möglich. Versagt etwa ein Knoten, auf dem OSD-Pods liefen, sorgt Rook nach Ablauf einer in Ceph konfigurierten Frist dafür, dass ein entsprechender OSD-Pod auf einem anderen Clusterknoten startet. Rook nutzt hier die Auto-Healing-Fähigkeiten von Ceph: Fällt diesem ein OSD aus, sodass nicht mehr für alle binären Objekte im Speicher die nötige Anzahl an Replikas existiert, kopiert Ceph die betroffenen Objekte automatisch auf andere OSDs. Die Applikation des Kunden merkt von diesem Vorgang gar nichts, sie greift permanent wie gewohnt auf ihr Volume zu.
Ein gewisses Risiko lässt sich bei diesem Ansatz allerdings nicht leugnen. Ceph ist hochkomplex und ganz unabhängig davon, ob der Admin mit Crush oder anderen Parametern des Clusters experimentieren möchte – er sollte sich auch mit der Technik auskennen. Denn spätestens wenn sich der Cluster unerwartet verhält oder es ein Problem zu debuggen gibt, nützt auch die schönste Abstraktion durch Rook nichts mehr. Weiß der Admin dann nicht, was er tut, droht im schlimmsten Fall der Verlust von Daten im Ceph-Cluster.
Immerhin ist den Rook-Entwicklern diese Problematik aber durchaus klar – und sie arbeiten daran, verschiedene Ceph-Funktionen künftig ebenfalls über die Rook-APIs erreichbar zu machen. Das umfasst ausdrücklich auch Crush.
Monitoring, Alerting, Trending
Auch wenn das durch Rook aufgesetzte und betriebene Ceph weitestgehend selbstverwaltet sein soll, möchte der Admin zumindest wissen, was gerade in seinem Ceph passiert. Praktisch: Ceph kommt ab Werk mit einer Vielzahl von Schnittstellen, um Metrikdaten über die aktuelle Nutzung und den Zustand des Clusters zu exportieren. Rook konfiguriert eben diese Schnittstellen, sodass sie von außerhalb nutzbar werden.
Natürlich gibt es von Prometheus, das sich ja ebenfalls zur Riege der hippen Cloud-Ready-Apps zählt, im Netz fertige Kubernetes-Templates, die in Sekundenschnelle einen kompletten MAT-Cluster mit Prometheus aus der Taufe heben [7]. Die Entwickler von Rook bieten ihrerseits wiederum die passenden Pods an, die das Ceph aus Rook mit eben jenem Prometheus-Container verdrahten. Eine Anleitung im Detail findet sich auf der Rook-Website [8].
Das Ende vom Lied ist eine komplette Lösung für Monitoring, Alerting und Trending inklusive bunter Dashboards in Grafana (Abbildung 4), die dem Admin verraten, wie es um seinen Ceph-Cluster gerade bestellt ist.

Abbildung 4: Praktisches Gespann: Prometheus und Grafana ermöglichen es, einen Ceph-Cluster zu überwachen.
Die Zukunft im Blick
Rook ist übrigens keinesfalls darauf ausgelegt, ausschließlich mit Ceph zu funktionieren, auch wenn dieser Eindruck im Verlauf des Artikels entstanden sein mag. Stattdessen haben die Entwickler großes vor: Cockroach DB [9] etwa steht als redundante, hochperformante SQL-Datenbank ebenfalls auf der To-do-Liste der Rook-Leute wie Minio [10], eine Art Konkurrenzprodukt zu Ceph.
Doch sei davor gewarnt, mit diesen Storage-Lösungen bereits produktive Systeme zu bauen. Beide Treiber befinden sich mitten in der Entwicklung. Auch Ceph ist wie Rook selbst als Beta getagt. Die Kombination Ceph und Rook dürfte aber die mit Abstand am weitesten verbreitete sein, sodass Kinderkrankheiten großen Stils nicht zu erwarten sind.
Hinter Rook steckt übrigens das amerikanische Unternehmen Upbound, das sich selbst als Cloud-Native Kubernetes-Provider versteht. Sonderlich viele Namen finden sich in der Maintainer-Liste allerdings nicht: Neben zwei Leuten von Upbound ist dort aber auch ein Red-Hat-Mitarbeiter verzeichnet, sodass man sich um die Zukunft des Projekts wohl eher keine Sorgen machen muss.
Freilich hat Red Hat selbst ein Interesse daran, eine möglichst gute Verbindung zwischen Kubernetes und Ceph zu schaffen, schließlich vermarktet man Ceph auch kommerziell als Ersatz für konventionellen Storage. Da ist es äußerst praktisch, dass Rook als freie Software daherkommt und unter den Bedingungen der Apache-Lizenz 2.0 steht.
Fazit
Eigentlich ist die Idee hinter Rook nicht sonderlich revolutionär: Die über Jahre hinweg erprobte Storage-Lösung Ceph in Container zu verpacken und diese dann in Kubernetes auszurollen, das liegt eigentlich auf der Hand. Die Art und Weise, wie Rook das Problem angeht, beeindruckt allerdings. Denn in der Lösung für die vermeintlich triviale Aufgabe stecken viel Hirnschmalz, viel Entwicklung und erkennbar auch viel Qualitätssicherung. Den Rook-Leuten ist durchaus klar, dass sie es mit Daten zu tun haben, also dem Gold des 21. Jahrhunderts, und mit dem gehen sie sehr sorgfältig um.
Dafür, dass Rook offiziell noch im Betastadium steckt, funktioniert es bereits ausgezeichnet. Wer versuchen will, Kubernetes und Ceph zu verheiraten, sollte auf jeden Fall einen Blick auf Rook werfen. Bis dato handelt es sich um die beste Lösung für dieses Problem.
Das Versprechen von redundantem Speicher für Cloud-Native-Apps hält Rook jedenfalls ein: Ein Rook-Volume unterscheidet sich nicht von einem typischen Kubernetes-Volume, was die Innensicht betrifft. Im Hintergrund sorgt Rook aber dafür, dass Replikation und Redundanz durch Ceph entstehen. Das Dilemma, dass sich weder die Containerumgebung noch die Entwickler noch der Kunde um die Redundanz von Speicher kümmern, schafft Rook aus der Welt.
Infos
-
Open Stack: https://www.openstack.org
-
Kubernetes: https://kubernetes.io
-
Docker: https://www.docker.com
-
Ceph: https://ceph.com
-
Rook-Namespace-Beispiele: https://github.com/rook/rook/tree/master/cluster/examples/kubernetes
-
Prometheus für Kubernetes: https://github.com/prometheus/prometheus/blob/master/documentation/examples/prometheus-kubernetes.yml
-
Prometheus und Rook: https://rook.io/docs/rook/v0.7/monitoring.html
-
Cockroach DB:https://github.com/cockroachdb
-
Minio:https://www.minio.io






