Ceph auf Bare-Metal-Kubernetes: So funktioniert es wirklich
- Ceph
- Rook
- Kubernetes
- RBD
- CephFS
- storage
1. Die Grundlage: Was Ceph ist und warum es auf Bare Metal passt
Ceph ist eine verteilte Speicher-Engine, die unabhängige Datenträger auf unabhängigen Maschinen zu einem gemeinsamen Speicherpool zusammenfasst. Einen zentralen Storage-„Server“ im klassischen Sinn gibt es nicht. Drei Eigenschaften prägen das System:
- Keine zentrale Standortabfrage. Clients berechnen mit einem deterministischen Algorithmus (CRUSH), wo Daten liegen, statt für jede Anfrage einen Metadatenserver zu fragen.
- Replikation als Standard. Jedes Objekt wird auf mehrere OSDs auf mehreren Hosts geschrieben. Die Ausfalldomäne ist ein Host, ein Rack oder die Ebene, die in den CRUSH-Regeln festgelegt ist.
- Eine Engine, mehrere Schnittstellen. Blockspeicher (RBD), ein gemeinsam nutzbares Dateisystem (CephFS) und Objektspeicher (S3 über RGW) bauen auf demselben replizierten Objektspeicher (RADOS) auf.
Warum Ceph auf Bare-Metal-Kubernetes betreiben?
- On-Premises steht kein verwalteter Blockspeicher wie in einer Cloud bereit. Stattdessen gibt es physische Server mit Datenträgern; Ceph macht daraus einen Speicher mit einer ähnlichen Rolle wie EBS.
- Rook macht die Verwaltung dieser Datenträger zu einer Kubernetes-Aufgabe: Geräteinventar, Daemon-Deployment und Upgrades werden über Reconciliation-Schleifen gesteuert statt über einzelne SSH-Sitzungen.
- Der Volume-Client, also der Kernel-RBD-Treiber, läuft im selben Host-Kernel wie die Pods. Auf Bare Metal erreicht ein Schreibzugriff die physischen Datenträger über einen kurzen Pfad: Pod → Kernel → Netzwerk → OSD.
Die entscheidende Kapazitätsrechnung: Bei dreifacher Replikation beträgt die nutzbare Kapazität raw / 3. Der Referenzcluster dieses Artikels verwendet 7 HDDs, eine je Storage-Host, mit jeweils etwa 0,47 TiB → 3,3 TiB Rohkapazität → etwa 1,1 TiB nutzbar. Jede Diskussion über fehlenden Speicherplatz beginnt mit dieser Division.
Der akzeptierte Zielkonflikt: Storage-Traffic teilt sich Netzwerkschnittstelle und Kernel eines Knotens mit den Workloads, und jeder Schreibzugriff wartet auf den langsamsten der drei beteiligten Datenträger. Für viele Workloads ist das ausreichend. Es ist eine zu berücksichtigende Architekturgrenze, kein Defekt.
2. Die Control Plane: Rook
Rook ist ein Kubernetes-Operator, also ein Regelkreis mit administrativen Zugangsdaten. Er übersetzt Custom Resources in laufende Software:
CephCluster→ MON-, MGR- und OSD-DaemonsCephBlockPool→ ein RADOS-Pool mit Größen- und ReplikationseinstellungenCephFilesystem→ MDS-Daemons sowie Metadaten- und DatenpoolsCephObjectStore→ RGW-Daemons und Objektpools
Was Rook übernimmt:
- Initialisierung des Clusters: Beim ersten Reconcile werden FSID, monmap und Admin-Keyring erzeugt.
- Geräteerkennung über das
rook-discover-DaemonSet und einmaligeosd-prepare-Jobs, die ausgewählte Geräte bereinigen, mit BlueStore vorbereiten und die OSDs in die CRUSH-Map aufnehmen. - Deployment der Ceph-Daemons als Deployments oder DaemonSets sowie deren laufende Verwaltung: Neustarts, Upgrades und Bereinigung von Knoten.
- Deployment und Konfiguration der CSI-Treiber, also Provisioner und Node-Plugins, mit cephx-Zugangsdaten.
- Meldung des Clusterzustands über Statusbedingungen der Custom Resources und Prometheus.
Was Rook NICHT übernimmt:
- Rook liegt nicht im Datenpfad. Sobald ein Volume eingebunden und gemountet ist, greifen Pods über den Kernel-Client direkt auf OSDs zu. Der Operator-Pod könnte gelöscht werden, ohne dass bereits gemountete Volumes allein deshalb aufhören, Lese- und Schreibzugriffe zu bedienen.
- Rook platziert keine Objekte, repliziert keine Daten und bedient keine I/O-Anfragen. Das erledigen die Ceph-Daemons.
- Rook legt keine PersistentVolumes an. Dafür sind die CSI-Provisioner-Sidecars zuständig.
Das passende mentale Modell: Rook verwaltet den Lebenszyklus des Clusters von der Einrichtung bis zum laufenden Betrieb. CSI verwaltet den Lebenszyklus der Volumes. Die Ceph-Daemons stellen den eigentlichen Speicher bereit. Zur Laufzeit sind diese drei Aufgaben voneinander trennbar.
Ein übertragbares Detail des Referenzclusters: Operator, MONs und RGWs laufen auf Hosts, die keine OSDs bereitstellen. So konkurrieren Control-Plane-Daemons nicht mit OSDs um Datenträger-I/O, und der Ausfall eines Storage-Hosts gefährdet weder das Quorum noch den S3-Endpunkt.
3. Die Speicher-Engine: OSD, MON und MGR
OSD — ein Daemon, ein Datenträger
Ein OSD (Object Storage Daemon) verwaltet in diesem Aufbau genau ein rohes Blockgerät. Das Verhältnis lautet: 1 OSD = 1 Datenträger. Die sieben HDDs des Referenzclusters entsprechen sieben OSDs auf jeweils unterschiedlichen Hosts. Deshalb verwenden seine Pools failureDomain: host und size: 3: Jedes Objekt liegt auf drei Hosts und übersteht den Verlust von zwei dieser Hosts.
Im Inneren eines OSDs:
- BlueStore ist die Speicher-Engine. Objektdaten werden ohne zwischengeschaltetes Dateisystem direkt auf das rohe Gerät geschrieben. BlueStore verwaltet Platzbelegung, Prüfsummen und Kompression selbst.
- RocksDB über BlueFS hält die Metadaten: Objektschlüssel, Extent-Zuordnungen und Statistiken. Das WAL/DB-Gerät für RocksDB kann ein separater, schnellerer Datenträger sein. Warum das wichtig ist, zeigt Abschnitt 5.
- Jeder OSD ist für einige Placement Groups Primary und für andere Replikat. Der Primary empfängt Schreibzugriffe, persistiert sie lokal, leitet sie an die Replikate weiter und bestätigt sie erst anschließend.
- OSDs prüfen gegenseitig ihre Erreichbarkeit über Heartbeats und melden Ausfälle an die MONs. Die MONs markieren einen OSD erst nach ausreichend unabhängigen Meldungen als
down; ein einzelner unzuverlässiger Peer soll keinen gesunden OSD aus dem Betrieb nehmen.
MON — die Map, nicht der I/O-Pfad
Der MON verwaltet die Cluster-Map: den maßgeblichen Zustand der vorhandenen Komponenten (monmap, osdmap, CRUSH-Map, PG-Map und MDS-Map) sowie die Zugriffsberechtigungen. Drei MONs bilden ein Paxos-Quorum und tolerieren einen Ausfall. Zwei MONs bieten dagegen keine Ausfalltoleranz, da weiterhin beide für eine Mehrheit benötigt werden.
Wichtige Zusammenhänge:
- Clients laden die Map einmal, halten sie im Cache und abonnieren inkrementelle Aktualisierungen. Der MON wird nicht für jede I/O-Operation abgefragt. Ein Ausfall beeinträchtigt die Verteilung von Maps und Verwaltungsoperationen, liegt aber nicht direkt zwischen Pod und Daten.
- Der Verlust des MON-Quorums stoppt laufende I/O-Operationen nicht zwangsläufig sofort. Clients können mit der letzten bekannten Map weiterarbeiten. Die Control Plane kann jedoch keine neuen Platzierungsentscheidungen mehr veröffentlichen.
- Die Platzierung der MONs muss bewusst erfolgen: Im Referenzcluster laufen die drei MONs auf Hosts ohne Storage-Datenträger. Ein Geräte- oder Knotenausfall in der Storage-Ebene verkleinert somit nicht gleichzeitig das Quorum.
MGR — Telemetrie und Automatisierung
Die MGR-Daemons bilden ein Active/Standby-Paar. Sie speichern keine Nutzdaten und bedienen keine Client-I/O-Anfragen. Der aktive MGR führt die Module aus, die Ceph im Betrieb handhabbar machen:
- prometheus exporter — Metriken je OSD und Pool, die im Referenzaufbau von einem Exporter-DaemonSet je Knoten erfasst werden
- dashboard — die Weboberfläche
- pg_autoscaler — hält die Anzahl der Placement Groups über die Pools hinweg im passenden Bereich
- crash — sammelt Daemon-Absturzberichte der Crash-Collector auf den Knoten
Fällt der aktive MGR aus, übernimmt der Standby innerhalb von Sekunden. MGR-Abstürze erzeugen zwar Health-Warnungen, liegen aber außerhalb des direkten Datenpfads der Workloads.
Weitere Komponenten: Das MDS-Paar aus aktivem Daemon und Hot Standby bedient nur die CephFS-Metadaten. Dateiinhalte durchlaufen den MDS nicht; Clients lesen und schreiben direkt über OSDs. Das RGW-Paar stellt den Objektspeicher bereit. Anders als MON und MGR liegt RGW im Datenpfad seiner Schnittstelle: Es übersetzt S3-Anfragen über librados in RADOS-Zugriffe.
4. Der Datenpfad: Einen Schreibzugriff verfolgen
Hier wird das Zusammenspiel konkret. Ein Volume hat zwei unterschiedliche Phasen: die einmalige Einrichtung und den Datenpfad, der bei jedem write() durchlaufen wird.
Phase A — Provisionierung und Mount beim Pod-Start
Pod-Spezifikation → PVC → K8s-API
→ CSI-Provisioner-Deployment (Sidecar beobachtet PVC-Events)
→ legt RBD-Image im Pool an (mit cephx-Zugangsdaten aus einem Secret)
→ liefert PV mit VolumeHandle zurück
→ kubelet auf dem Zielknoten
→ gRPC "NodeStageVolume" an das CSI-Node-Plugin (privilegierter DaemonSet-Pod)
→ rbd map → Kernel-RBD-Treiber legt /dev/rbdX auf dem HOST an
→ mkfs.ext4/xfs (Dateisystemmodus) oder rohes Gerät (Blockmodus)
→ "NodePublishVolume" → Bind-Mount in den Dateisystem-Namespace des Pods
Beteiligt sind das external-provisioner-Sidecar im CSI-Provisioner-Deployment, kubelet und das CSI-Node-Plugin-DaemonSet. Provisioner und Node-Plugin sind unterschiedliche Softwarekomponenten: Das Provisioner-Deployment legt Volumes über die Ceph-API an; das Node-Plugin bindet sie auf jedem Bare-Metal-Knoten ein, formatiert und mountet sie. Der Provisioner übernimmt keine Node-I/O, und das Node-Plugin legt die Volumes nicht selbst an.
„Attach“ bedeutet bei RBD nicht, dass ein Gerät im SCSI-Sinn angeschlossen wird. Das Volume ist über das Netzwerk angebunden. Das Mapping veranlasst das rbd-Modul im Host-Kernel, die zugehörigen Objekte über das Netzwerk anzusprechen.
Nach dem Mount ist die Einrichtungsarbeit des Node-Plugins abgeschlossen. Bei RBD verlässt es den eigentlichen Datenpfad vollständig.
Phase B — Der eigentliche Schreibzugriff
1. Anwendung ruft write(fd, buf) auf
2. ext4/xfs (Dateisystemmodus) → Page Cache / Direct I/O
3. Kernel-RBD-Treiber (krbd) — Host-Kernel, KEIN Container
4. krbd berechnet die Platzierung LOKAL:
hash(object) mod pg_num → Placement Group (PG)
CRUSH(PG, osdmap) → geordnete OSD-Liste [Primary, Replikat, Replikat]
5. Eine Nachricht über das Netzwerk an den Primary-OSD
6. Primary schreibt auf sein BlueStore-Gerät UND leitet an 2 OSDs auf anderen Hosts weiter
7. Beide Replikate persistieren die Daten und bestätigen sie
8. Primary bestätigt dem Client → write() kehrt zurück
Wer NICHT in diesem Pfad liegt:
- Der MON — die Map wurde beim Mount gecacht
- Rook — gleicht Custom Resources ab, transportiert aber keine Nutzdaten
- Die K8s-API — kubelet hat die Einrichtung beim Mount erledigt
- Der CSI-Provisioner — das Volume existiert bereits
- Der CSI-Node-Plugin-Pod — der Kernel-Treiber verwaltet das Gerät
Das ist der Kern dieser Architektur: Alle Komponenten, die das Volume „verwalten“, liegen außerhalb des laufenden RBD-Datenpfads. Ein Schreibzugriff aus einem Pod läuft über den lokalen Kernel zum Primary-OSD und weiter zu zwei Replikaten. Drei Netzwerkstrecken, drei persistente Schreibvorgänge auf Datenträgern.
Das Latenzbudget: Die Schreiblatenz lässt sich grob als Netzwerk-RTT (×3) plus dem langsamsten der drei Datenträger-Flushes betrachten. Bei HDD-basierten OSDs dominiert die Rotationslatenz: Ein- bis zweistellige Millisekunden pro synchronem Schreibzugriff sind üblich, noch bevor der Metadaten-Overhead von BlueStore berücksichtigt wird. Der Durchsatz wächst mit der Verteilung über Placement Groups; die Latenz sinkt nicht automatisch durch zusätzliche HDDs, da sie vom einzelnen Datenträger begrenzt wird.
Die CephFS-Variante: Das Ziel bleibt RADOS, der Client ist jedoch ein anderer. In der hier beschriebenen FUSE-Variante mountet das Node-Plugin das Dateisystem mit ceph-fuse, einem Userspace-Daemon im Plugin-Pod, und bindet es in den Anwendungspod ein. Anders als beim Kernel-RBD-Pfad liegt der Plugin-Pod dann im Datenpfad: Daten fließen von der Anwendung über FUSE zu den OSDs; Metadatenoperationen gehen zum aktiven MDS. Dateiinhalte werden weiterhin direkt über OSDs übertragen. Der Zielkonflikt besteht zwischen gemeinsam nutzbaren RWX-Mounts mit Zugriff aus mehreren Pods und einem zusätzlichen Userspace-Schritt je Operation.
5. Praxisbezug: So sieht der Aufbau in einem realen Cluster aus
Die Referenztopologie umfasst 13 Bare-Metal-Knoten. Sieben Storage-Hosts stellen jeweils genau einen HDD-OSD mit etwa 0,47 TiB und BlueStore bereit. Drei Storage-Control-Hosts betreiben MONs mit einem Quorum aus drei Instanzen, das RGW-Paar und den Operator, aber keine OSDs. Ein Kubernetes-Control-Plane-Knoten betreibt keine Ceph-Daemons. Ein Edge-Knoten führt ausschließlich das CSI-RBD-Plugin aus, damit dort eingeplante Pods ebenfalls RBD-Volumes mounten können. Zwölf Pools und etwa 170 Placement Groups befinden sich im Zustand active+clean und versorgen ungefähr 95 gebundene PVCs.
Die Storage Classes zeigen die Aufteilung der Workloads:
- Eine allgemeine RBD-Klasse — Reclaim Policy
Delete, sofortige Bindung und aktivierte Erweiterung. Hier liegt der Zustand von Anwendungen wie Message Queues, Datenbanken, Key-Value-Stores, Log-Stores und Container-Registries. Wird das PVC gelöscht, wird auch das RBD-Image entfernt. - Eine RBD-Klasse für Datenbanken — Reclaim Policy
Retain, Bindung überWaitForFirstConsumerund aktivierte Erweiterung.Retainbedeutet, dass ein Administrator das zugrunde liegende Image manuell löschen muss. Das Löschen eines Datenbank-PVCs zerstört somit nicht automatisch die Daten.WaitForFirstConsumerverschiebt die Volume-Erstellung, bis der Scheduler den Pod einem Knoten zugeordnet hat. - Eine CephFS-Klasse — für die wenigen Workloads, die gemeinsam nutzbare
ReadWriteMany-Mounts benötigen. - Eine Bucket-Klasse — stellt über
ObjectBucketClaimsS3-Buckets für Anwendungen bereit, die direkt mit Objektspeicher arbeiten.
Zwei RBD-Klassen greifen auf denselben Pool zu und unterscheiden sich nur durch ihre Policies. Dieses Muster ist übertragbar; es ist keine Besonderheit des einzelnen Clusters.
Health-Warnungen lesen — typische Zusammenhänge bei HDD-basiertem Ceph:
- „4 OSDs experiencing stalled reads in db device of BlueFS“ und „1 OSD with slow operations in BlueStore“: RocksDB-WAL und -DB von BlueStore liegen auf derselben HDD wie die Nutzdaten. Metadaten-Kompaktierung und Client-I/O konkurrieren um denselben Datenträger. Der übliche Ansatz ist ein dediziertes
block.db-/block.wal-Gerät auf einer NVMe oder SSD. Ein schneller Datenträger kann dabei von mehreren OSDs desselben Hosts gemeinsam genutzt werden. RocksDB-Metadatenverkehr ist vergleichsweise klein, aber latenzempfindlich. - „mon is low on available space“: MONs schreiben fortlaufend kleine Mengen persistenten Zustands. Ein Control-Host mit kleinem Root-Dateisystem warnt entsprechend. Anfangs wirkt das unkritisch, bis der Platz tatsächlich knapp wird.
- „2 mgr modules recently crashed“: Den betroffenen Regelkreis neu starten und die vom Crash-Collector erfassten Berichte prüfen. Die Abwesenheit des MGR lag nicht im Datenpfad. Dass Workloads davon nichts bemerkten, entspricht der Trennung dieser Aufgaben.
Betriebliche Schlussfolgerungen aus diesem Cluster:
- Ein Datenträger je Host → Die Ausfalldomäne
hostfolgt aus der Verteilung der Hardware. Da alle Replikate auf unterschiedlichen Hosts liegen müssen, orientiert sich der Spielraum anhosts - 2, nicht allein an der Anzahl der Datenträger. - Dreifache Replikation auf sieben Hosts verbraucht etwa zwei Drittel der Rohkapazität für Replikate. Erasure Coding verändert diese Rechnung, erhöht bei HDDs aber die Anforderungen an den I/O-Pfad und die Latenz.
- Volumes lassen sich im Betrieb erweitern:
allowVolumeExpansion: truebei den RBD-Klassen erlaubt dem Resizer-Sidecar, das RBD-Image zu vergrößern. Den Pool selbst zu erweitern bedeutet im Referenzaufbau, weitere Hosts hinzuzufügen — die auf Bare Metal aufwendigere Aufgabe.
Die Zusammenfassung: Rook, API-Server, Provisioner und die Einrichtungsaufgaben der Plugins gehören zur Control Plane. Sie legen Ressourcen an, mounten und verwalten sie und treten anschließend aus dem RBD-Datenpfad heraus. Ceph-Clients und OSDs bilden die Data Plane: Sie berechnen die Platzierung lokal und kommunizieren direkt miteinander. Nach dem Mount unterscheidet sich ein Pod, der auf ein PVC auf Bare-Metal-Kubernetes schreibt, im Kern nicht von einem Prozess auf einem physischen Host, der auf replizierten Netzwerkspeicher zugreift. Darauf beruht das Zusammenspiel.
Quellen und verwandte Beiträge
- Ceph-Architektur zu RADOS, Daemon-Aufgaben, Platzierung und Client-Schnittstellen.
- Rook-Ceph-Dokumentation zur Speicherverwaltung in Kubernetes und den Aufgaben des Operators.
- Ceph CSI zur Provisionierung von RBD- und CephFS-Volumes sowie zu Node-Plugins.
- Kubernetes StorageClasses zu Reclaim Policy, Binding Mode und Volume-Erweiterung.
- Ceph-Warnungen verstehen, bevor der Cluster geändert wird für eine Diagnose anhand konkreter Health-Kennungen.
- Ein Snapshot ist noch kein Restore-Plan zu Recovery-Bausteinen und zur Prüfung der Wiederherstellung.
Verwandte Beiträge
RunbooksStorage
Ceph-Warnungen verstehen, bevor der Cluster geändert wird
Ceph-Health-Kennungen einordnen, bevor Wiederherstellungsschritte gewählt oder Workload-Symptome zugeordnet werden.
ErkenntnisseStorage
Ein Snapshot ist noch kein Restore-Plan
Volume-Snapshots nur als einen Recovery-Baustein behandeln und Restore, Konsistenz, Rechte und Zielcluster-Kompatibilität prüfen.