Container Storage Interface (CSI) ist eine einheitliche Schnittstelle für die Interaktion zwischen Kubernetes und Speichersystemen. Kurz gesagt haben wir bereits darüber gesprochen, , und heute betrachten wir näher die Kombination von CSI und Ceph: Wir zeigen, wie mit dem Kubernetes-Cluster verbunden wird.
Der Artikel enthält reale, wenn auch etwas vereinfachte Beispiele zur leichteren Verständlichkeit. Installation und Konfiguration von Ceph- und Kubernetes-Clustern werden nicht behandelt.
Interessiert Sie, wie das funktioniert?

Nun, Sie haben einen Kubernetes-Cluster bereitgestellt, zum Beispiel . Daneben läuft ein Ceph-Cluster, den Sie auch beispielsweise mit diesem einrichten können. Ich hoffe, es muss nicht erwähnt werden, dass zwischen ihnen für den Produktionsbetrieb ein Netzwerk mit einer Bandbreite von mindestens 10 Gbit/s bestehen sollte.
Wenn Sie das alles haben, legen wir los!
Zuerst gehen wir zu einem der Knoten im Ceph-Cluster und überprüfen, ob alles in Ordnung ist:
ceph health
ceph -sDann erstellen wir sofort einen Pool für RBD-Volumes:
ceph osd pool create kube 32
ceph osd pool application enable kube rbdWechseln wir zum Kubernetes-Cluster. Dort installieren wir zunächst den Ceph CSI-Treiber für RBD. Wir werden dies wie vorgesehen über Helm installieren.
Wir fügen das Repository mit dem Chart hinzu und erhalten eine Menge von Variablen für das ceph-csi-rbd-Chart:
helm repo add ceph-csi https://ceph.github.io/csi-charts
helm inspect values ceph-csi/ceph-csi-rbd > cephrbd.ymlJetzt müssen wir die Datei cephrbd.yml ausfüllen. Dazu erfahren wir die ID des Clusters und die IP-Adressen der Monitore in Ceph:
ceph fsid # so erfahren wir den clusterID
ceph mon dump # und hier sehen wir die IP-Adressen der MonitoreDie erhaltenen Werte tragen wir in die Datei cephrbd.yml ein. Nebenbei aktivieren wir die Erstellung von PSP (Pod Security Policies). Die Optionen in den Abschnitten nodeplugin und provisioner sind bereits in der Datei vorhanden und können wie unten gezeigt angepasst werden:
csiConfig:
- clusterID: "bcd0d202-fba8-4352-b25d-75c89258d5ab"
monitors:
- "v2:172.18.8.5:3300/0,v1:172.18.8.5:6789/0"
- "v2:172.18.8.6:3300/0,v1:172.18.8.6:6789/0"
- "v2:172.18.8.7:3300/0,v1:172.18.8.7:6789/0"
nodeplugin:
podSecurityPolicy:
enabled: true
provisioner:
podSecurityPolicy:
enabled: trueAls nächstes bleibt uns nur noch, das Chart im Kubernetes-Cluster zu installieren.
helm upgrade -i ceph-csi-rbd ceph-csi/ceph-csi-rbd -f cephrbd.yml -n ceph-csi-rbd --create-namespaceGroßartig, der RBD-Treiber funktioniert!
Erstellen wir eine neue StorageClass in Kubernetes. Dazu müssen wir wieder ein wenig mit Ceph arbeiten.
Wir erstellen einen neuen Benutzer in Ceph und gewähren ihm Schreibrechte im Pool kube:
ceph auth get-or-create client.rbdkube mon 'profile rbd' osd 'profile rbd pool=kube'Und jetzt sehen wir den Zugangsschlüssel dort ebenfalls:
ceph auth get-key client.rbdkubeDer Befehl gibt etwa Folgendes aus:
AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==Wir werden diesen Wert in das Secret im Kubernetes-Cluster eintragen — genau dort, wo er benötigt wird. userKey:
---
apiVersion: v1
kind: Secret
metadata:
name: csi-rbd-secret
namespace: ceph-csi-rbd
stringData:
# Die Werte der Schlüssel entsprechen dem Benutzernamen und seinem Schlüssel, wie im
# Ceph-Cluster angegeben. Die Benutzer-ID muss Zugriff auf den Pool haben,
# der in der Storage Class angegeben ist.
userID: rbdkube
userKey:Nun erstellen wir unser Secret:
kubectl apply -f secret.yamlIm Anschluss benötigen wir ein Manifest für die StorageClass in etwa folgender Form:
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
clusterID:
pool: kube
imageFeatures: layering
# Diese Secrets müssen die Anmeldedaten für den Zugriff
# auf Ihren Pool enthalten.
csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-rbd
csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-rbd
csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-rbd
csi.storage.k8s.io/fstype: ext4
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- discardMuss ausgefüllt werden clusterID, den wir bereits mit dem Befehl ceph fsid, herausgefunden haben, und dieses Manifest im Kubernetes-Cluster anwenden:
kubectl apply -f storageclass.yamlUm die Funktionsweise der Cluster in Verbindung zu überprüfen, erstellen wir diesen PVC (Persistent Volume Claim):
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: rbd-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: csi-rbd-scSchauen wir uns gleich an, wie Kubernetes den angeforderten Volume in Ceph erstellt hat:
kubectl get pvc
kubectl get pvSieht gut aus! Und wie sieht es auf der Ceph-Seite aus?
Wir holen die Liste der Volumes im Pool und sehen uns die Informationen zu unserem Volume an:
rbd ls -p kube
rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653 # hier wird natürlich eine andere ID des Volumes angezeigt, die von der vorherigen Befehlsausgabe stammtJetzt schauen wir uns an, wie die Größenanpassung des RBD-Volumes funktioniert.
Wir ändern die Größe des Volumes in der Manifestdatei pvc.yaml auf 2Gi und wenden sie an:
kubectl apply -f pvc.yamlWarten wir, bis die Änderungen wirksam werden, und sehen uns die Größe des Volumes erneut an.
rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653
kubectl get pv
kubectl get pvcWir sehen, dass sich die Größe des PVC nicht geändert hat. Um die Ursache herauszufinden, können wir Kubernetes um eine Beschreibung des PVC im YAML-Format bitten:
kubectl get pvc rbd-pvc -o yamlUnd da ist das Problem:
message: Warten auf den Nutzer, um einen Pod (neu) zu starten, um die Größenänderung des Dateisystems auf dem Volume auf dem Knoten abzuschließen. type: FileSystemResizePending
Das bedeutet, dass das Laufwerk vergrößert wurde, das Dateisystem darauf jedoch nicht.
Um das Dateisystem zu erweitern, muss das Volume eingehängt werden. Unser erstelltes PVC/PV wird derzeit jedoch nicht verwendet.
Wir können einen Test-Pod wie folgt erstellen:
---
apiVersion: v1
kind: Pod
metadata:
name: csi-rbd-demo-pod
spec:
containers:
- name: web-server
image: nginx:1.17.6
volumeMounts:
- name: mypvc
mountPath: /data
volumes:
- name: mypvc
persistentVolumeClaim:
claimName: rbd-pvc
readOnly: falseUnd jetzt schauen wir uns das PVC an:
kubectl get pvcDie Größe hat sich geändert, alles in Ordnung.
Im ersten Teil haben wir mit einem RBD-Blockgerät gearbeitet (es steht für Rados Block Device), aber das ist nicht möglich, wenn verschiedene Mikrodienste gleichzeitig auf diese Festplatte zugreifen müssen. Für die Arbeit mit Dateien, und nicht mit einem Abbild der Festplatte, ist CephFS viel besser geeignet.
Am Beispiel von Ceph-Clustern und Kubernetes richten wir CSI und die anderen notwendigen Entitäten für die Arbeit mit CephFS ein.
Wir holen uns die Werte aus dem benötigten neuen Helm-Chart:
helm inspect values ceph-csi/ceph-csi-cephfs > cephfs.ymlWieder müssen wir die Datei cephfs.yml ausfüllen. Wie zuvor helfen die Ceph-Kommandos dabei:
ceph fsid
ceph mon dumpWir füllen die Datei mit Werten ungefähr so aus:
csiConfig:
- clusterID: "bcd0d202-fba8-4352-b25d-75c89258d5ab"
monitors:
- "172.18.8.5:6789"
- "172.18.8.6:6789"
- "172.18.8.7:6789"
nodeplugin:
httpMetrics:
enabled: true
containerPort: 8091
podSecurityPolicy:
enabled: true
provisioner:
replicaCount: 1
podSecurityPolicy:
enabled: trueBitte beachten Sie, dass die Adressen der Monitore in einfacher Form address:port angegeben werden. Für das Montieren von cephfs auf dem Knoten werden diese Adressen an das Kernelmodul übergeben, das noch nicht mit dem Protokoll der v2-Monitore arbeiten kann.
Wir ändern den Port für httpMetrics (dorthin wird Prometheus für die Monitoring-Metriken gehen), damit er nicht mit dem nginx-proxy in Konflikt gerät, der von Kubespray installiert wird. Möglicherweise benötigen Sie das nicht.
Wir installieren das Helm-Chart im Kubernetes-Cluster:
helm upgrade -i ceph-csi-cephfs ceph-csi/ceph-csi-cephfs -f cephfs.yml -n ceph-csi-cephfs --create-namespaceWir wechseln zu dem Ceph-Datenspeicher, um dort einen neuen Benutzer zu erstellen. In der Dokumentation steht, dass der Provisioner für CephFS Administratorrechte im Cluster benötigt. Aber wir werden einen separaten Benutzer mit eingeschränkten Rechten erstellen: fs ceph auth get-or-create client.fs mon 'allow r' mgr 'allow rw' mds 'allow rws' osd 'allow rw pool=cephfs_data, allow rw pool=cephfs_metadata'
Und sofort sehen wir seinen Zugriffsschlüssel, der uns später nützlich sein wird:ceph auth get-key client.fs
Wir erstellen separate Secrets und eine StorageClass.Nichts Neues, das haben wir bereits am Beispiel von RBD gesehen:
Nichts Neues, das haben wir bereits am Beispiel RBD gesehen:
---
apiVersion: v1
kind: Secret
metadata:
name: csi-cephfs-secret
namespace: ceph-csi-cephfs
stringData:
# Erforderlich für dynamisch erstellte Volumes
adminID: fs
adminKey:Wir wenden das Manifest an:
kubectl apply -f secret.yamlUnd jetzt – eine separate StorageClass:
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi-cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
clusterID:
# Name des CephFS-Dateisystems, in dem der Volume erstellt wird
fsName: cephfs
# (optional) Ceph-Pool, in dem die Volumendaten gespeichert werden
# pool: cephfs_data
# (optional) Durch Kommas getrennte Mount-Optionen für Ceph-fuse
# zum Beispiel:
# fuseMountOptions: debug
# (optional) Durch Kommas getrennte Mount-Optionen für CephFS im Kernel
# Siehe man mount.ceph für eine Liste dieser Optionen. Zum Beispiel:
# kernelMountOptions: readdir_max_bytes=1048576,norbytes
# Die Secrets sollten Berechtigungen für Admin und/oder Ceph-Nutzer enthalten.
csi.storage.k8s.io/provisioner-secret-name: csi-cephfs-secret
csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-cephfs
csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-cephfs
csi.storage.k8s.io/node-stage-secret-name: csi-cephfs-secret
csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-cephfs
# (optional) Der Treiber kann entweder ceph-fuse (fuse) oder ceph kernelclient (kernel) verwenden.
# Wenn nicht angegeben, wird das Standard-Mount verwendet,
# dies wird durch die Suche nach ceph-fuse und mount.ceph bestimmt
# mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
- debugFüllen wir das hier aus clusterID und wenden es in Kubernetes an:
kubectl apply -f storageclass.yamlÜberprüfung
Um zu überprüfen, wie im vorherigen Beispiel, erstellen wir PVC:
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: csi-cephfs-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 5Gi
storageClassName: csi-cephfs-scUnd überprüfen wir das Vorhandensein von PVC/PV:
kubectl get pvc
kubectl get pvWenn Sie die Dateien und Verzeichnisse in CephFS ansehen möchten, können Sie dieses Dateisystem irgendwo einbinden. Zum Beispiel wie unten gezeigt.
Gehen wir zu einem der Knoten im Ceph-Cluster und führen wir die folgenden Schritte aus:
# Точка монтирования
mkdir -p /mnt/cephfs
# Создаём файл с ключом администратора
ceph auth get-key client.admin >/etc/ceph/secret.key
# Добавляем запись в /etc/fstab
# !! Изменяем ip адрес на адрес нашего узла
echo "172.18.8.6:6789:/ /mnt/cephfs ceph name=admin,secretfile=/etc/ceph/secret.key,noatime,_netdev 0 2" >> /etc/fstab
mount /mnt/cephfsNatürlich ist ein solches Einhängen des FS auf einem Ceph-Knoten ausschließlich für Ausbildungszwecke geeignet, was wir in unseren . Ich denke nicht, dass jemand dies in der Produktion tun würde; das Risiko, wichtige Dateien versehentlich zu überschreiben, ist groß.
Zu guter Letzt lassen Sie uns überprüfen, wie es bei CephFS mit der Größenänderung des Volumes aussieht. Wir kehren zu Kubernetes zurück und bearbeiten unser Manifest für PVC – wir erhöhen die Größe zum Beispiel auf 7Gi.
Wenden wir die bearbeitete Datei an:
kubectl apply -f pvc.yamlSehen wir uns im eingebundenen Verzeichnis an, wie sich das Kontingent geändert hat:
getfattr -n ceph.quota.max_bytesFür die Ausführung dieses Befehls müssen Sie möglicherweise das Paket in das System installieren attr.
Die Augen haben Angst, aber die Hände handeln
Auf den ersten Blick erscheinen all diese Befehle und langen YAML-Manifeste kompliziert, aber in der Praxis kommen die Slyrm-Studenten recht schnell damit zurecht.
In diesem Artikel gehen wir nicht in die Tiefe — dafür gibt es die offizielle Dokumentation. Wenn Sie sich für die Details der Ceph-Speicherintegration mit einem Kubernetes-Cluster interessieren, helfen Ihnen diese Links:
Im Slyrm-Kurs können Sie noch einen Schritt weiter gehen und eine echte Anwendung in Kubernetes bereitstellen, die CephFS als Dateispeicher nutzt. Über GET/POST-Anfragen können Sie Dateien übertragen und aus Ceph abrufen.
Wenn Sie mehr an der Datenspeicherung interessiert sind, melden Sie sich für den an. Während der Beta-Testphase kann der Kurs zu einem ermäßigten Preis erlangt werden und Sie können Einfluss auf dessen Inhalt nehmen.
Autor des Artikels: Alexander Shvalov, praktizierender Ingenieur , Certified Kubernetes Administrator, Autor und Entwickler der Slyrm-Kurse.
Quelle: habr.com
