Praktisches Beispiel für die Anbindung von Ceph-basiertem Speicher an ein Kubernetes-Cluster

Container Storage Interface (CSI) ist eine einheitliche Schnittstelle für die Interaktion zwischen Kubernetes und Speichersystemen. Kurz gesagt haben wir bereits darüber gesprochen, über, und heute betrachten wir näher die Kombination von CSI und Ceph: Wir zeigen, wie Ceph-Speicher 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?

Praktisches Beispiel für die Anbindung von Ceph-basiertem Speicher an ein Kubernetes-Cluster

Nun, Sie haben einen Kubernetes-Cluster bereitgestellt, zum Beispiel kubespray. Daneben läuft ein Ceph-Cluster, den Sie auch beispielsweise mit diesem Playbook-Seteinrichten 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 -s

Dann erstellen wir sofort einen Pool für RBD-Volumes:

ceph osd pool create kube 32
ceph osd pool application enable kube rbd

Wechseln 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.yml

Jetzt 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 Monitore

Die 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: true

Als 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-namespace

Groß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.rbdkube

Der 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.yaml

Im 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:
  - discard

Muss 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.yaml

Um 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-sc

Schauen wir uns gleich an, wie Kubernetes den angeforderten Volume in Ceph erstellt hat:

kubectl get pvc
kubectl get pv

Sieht 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 stammt

Jetzt 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.yaml

Warten 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 pvc

Wir 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 yaml

Und 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: false

Und jetzt schauen wir uns das PVC an:

kubectl get pvc

Die 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.yml

Wieder müssen wir die Datei cephfs.yml ausfüllen. Wie zuvor helfen die Ceph-Kommandos dabei:

ceph fsid
ceph mon dump

Wir 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: true

Bitte 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-namespace

Wir 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.yaml

Und 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:
  - debug

Fü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-sc

Und überprüfen wir das Vorhandensein von PVC/PV:

kubectl get pvc
kubectl get pv

Wenn 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/cephfs

Natürlich ist ein solches Einhängen des FS auf einem Ceph-Knoten ausschließlich für Ausbildungszwecke geeignet, was wir in unseren Slurm-Kursen. 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.yaml

Sehen wir uns im eingebundenen Verzeichnis an, wie sich das Kontingent geändert hat:

getfattr -n ceph.quota.max_bytes

Fü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:

Allgemeine Prinzipien von Kubernetes mit Volumes
Dokumentation zu RBD
Integration von RBD und Kubernetes aus der Perspektive von Ceph
Integration von RBD und Kubernetes aus der Perspektive von CSI
Allgemeine Dokumentation zu CephFS
Integration von CephFS und Kubernetes aus der Perspektive von CSI

Im Slyrm-Kurs Kubernetes Basis 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 neuen Ceph-Kursan. 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 Southbridge, Certified Kubernetes Administrator, Autor und Entwickler der Slyrm-Kurse.

Quelle: habr.com

Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen 🔥 Zuverlässiges Webhosting mit DDoS-Schutz, VPS- und VDS-Server kaufen | ProHoster