Ein praktisches Beispiel für die Anbindung von Ceph-basiertem Speicher an einen Kubernetes-Cluster

Container Storage Interface (CSI) ist eine einheitliche Schnittstelle zwischen Kubernetes und Speichersystemen. Wir haben bereits kurz darüber gesprochen erzählt, und heute werfen wir einen genaueren Blick auf die Kombination von CSI und Ceph: Wir zeigen wie Verbinden Sie den Ceph-Speicher zum Kubernetes-Cluster.
Der Artikel enthält reale, wenn auch leicht vereinfachte Beispiele zur leichteren Wahrnehmung. Wir ziehen die Installation und Konfiguration von Ceph- und Kubernetes-Clustern nicht in Betracht.

Sie fragen sich, wie es funktioniert?

Ein praktisches Beispiel für die Anbindung von Ceph-basiertem Speicher an einen Kubernetes-Cluster

Sie haben also einen Kubernetes-Cluster zur Hand, der beispielsweise bereitgestellt wird Kubespray. In der Nähe arbeitet ein Ceph-Cluster, den Sie beispielsweise auch hier installieren können eine Reihe von Spielbüchern. Ich hoffe, es erübrigt sich zu erwähnen, dass für die Produktion zwischen ihnen ein Netzwerk mit einer Bandbreite von mindestens 10 Gbit/s vorhanden sein muss.

Wenn du das alles hast, lass uns gehen!

Gehen wir zunächst zu einem der Ceph-Clusterknoten und prüfen, ob alles in Ordnung ist:

ceph health
ceph -s

Als nächstes erstellen wir sofort einen Pool für RBD-Festplatten:

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

Kommen wir zum Kubernetes-Cluster. Dort installieren wir zunächst den Ceph CSI-Treiber für RBD. Wir werden wie erwartet über Helm installieren.
Wir fügen ein Repository mit einem Diagramm hinzu und erhalten einen Satz Variablen für das ceph-csi-rbd-Diagramm:

helm repo add ceph-csi https://ceph.github.io/csi-charts
helm inspect values ceph-csi/ceph-csi-rbd > cephrbd.yml

Jetzt müssen Sie die Datei cephrbd.yml ausfüllen. Ermitteln Sie dazu die Cluster-ID und IP-Adressen der Monitore in Ceph:

ceph fsid  # так мы узнаем clusterID
ceph mon dump  # а так увидим IP-адреса мониторов

Die erhaltenen Werte tragen wir in die Datei cephrbd.yml ein. Nebenbei ermöglichen wir die Erstellung von PSP-Richtlinien (Pod Security Policies). Optionen in Abschnitten Nodeplugin и Versorger bereits in der Datei vorhanden sind, können sie wie folgt korrigiert 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 müssen wir nur noch das Diagramm im Kubernetes-Cluster 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. Dies erfordert wiederum ein wenig Bastelei mit Ceph.

Wir erstellen einen neuen Benutzer in Ceph und geben ihm Schreibrechte für den Pool Kuppel:

ceph auth get-or-create client.rbdkube mon 'profile rbd' osd 'profile rbd pool=kube'

Sehen wir uns nun an, dass der Zugriffsschlüssel noch vorhanden ist:

ceph auth get-key client.rbdkube

Der Befehl gibt etwa Folgendes aus:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Fügen wir diesen Wert zu Secret im Kubernetes-Cluster hinzu – dort, wo wir ihn benötigen userKey:

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-rbd-secret
  namespace: ceph-csi-rbd
stringData:
  # Значения ключей соответствуют имени пользователя и его ключу, как указано в
  # кластере Ceph. ID юзера должен иметь доступ к пулу,
  # указанному в storage class
  userID: rbdkube
  userKey: <user-key>

Und wir schaffen unser Geheimnis:

kubectl apply -f secret.yaml

Als nächstes benötigen wir ein StorageClass-Manifest, etwa so:

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
   clusterID: <cluster-id>
   pool: kube

   imageFeatures: layering

   # Эти секреты должны содержать данные для авторизации
   # в ваш пул.
   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 Cluster-ID, was wir vom Team bereits gelernt haben ceph fsid, und wenden Sie dieses Manifest auf den Kubernetes-Cluster an:

kubectl apply -f storageclass.yaml

Um zu überprüfen, wie die Cluster zusammenarbeiten, erstellen wir den folgenden PVC (Persistent Volume Claim):

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-rbd-sc

Sehen wir uns gleich an, wie Kubernetes das angeforderte Volume in Ceph erstellt hat:

kubectl get pvc
kubectl get pv

Alles scheint großartig zu sein! Wie sieht das auf der Ceph-Seite aus?
Wir erhalten eine Liste der Volumes im Pool und sehen Informationen zu unserem Volume:

rbd ls -p kube
rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653  # тут, конечно же, будет другой ID тома, который выдала предыдущая команда

Sehen wir uns nun an, wie die Größenänderung eines RBD-Volumes funktioniert.
Ändern Sie die Volume-Größe im pvc.yaml-Manifest in 2Gi und wenden Sie es an:

kubectl apply -f pvc.yaml

Warten wir, bis die Änderungen wirksam werden, und schauen wir uns die Volume-Größe noch einmal 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 von PVC nicht verändert hat. Um herauszufinden, warum, können Sie Kubernetes nach einer YAML-Beschreibung des PVC abfragen:

kubectl get pvc rbd-pvc -o yaml

Hier ist das Problem:

Nachricht: Warten darauf, dass der Benutzer einen Pod (neu) startet, um die Größenänderung des Dateisystems des Volumes auf dem Knoten abzuschließen. Typ: FileSystemResizePending

Das heißt, die Festplatte ist gewachsen, das darauf befindliche Dateisystem jedoch nicht.
Um das Dateisystem zu vergrößern, müssen Sie das Volume mounten. In unserem Land wird das erzeugte PVC/PV derzeit in keiner Weise verwendet.

Wir können einen Test-Pod erstellen, zum Beispiel so:

---
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 nun schauen wir uns PVC an:

kubectl get pvc

Die Größe hat sich geändert, alles ist in Ordnung.

Im ersten Teil haben wir mit dem RBD-Blockgerät (es steht für Rados Block Device) gearbeitet, dies ist jedoch nicht möglich, wenn verschiedene Microservices gleichzeitig mit diesem Datenträger arbeiten müssen. CephFS eignet sich viel besser für die Arbeit mit Dateien als für die Arbeit mit Disk-Images.
Am Beispiel von Ceph- und Kubernetes-Clustern konfigurieren wir CSI und andere notwendige Entitäten für die Arbeit mit CephFS.

Holen wir uns die Werte aus dem neuen Helm-Diagramm, die wir brauchen:

helm inspect values ceph-csi/ceph-csi-cephfs > cephfs.yml

Auch hier müssen Sie die Datei cephfs.yml ausfüllen. Wie zuvor helfen Ceph-Befehle:

ceph fsid
ceph mon dump

Füllen Sie die Datei mit Werten wie diesen 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 Monitoradressen in der einfachen Form Adresse:Port angegeben werden. Um Cephfs auf einem Knoten zu mounten, werden diese Adressen an das Kernel-Modul übergeben, das noch nicht weiß, wie es mit dem v2-Monitor-Protokoll arbeiten soll.
Wir ändern den Port für httpMetrics (Prometheus wird dorthin gehen, um Metriken zu überwachen), damit es nicht zu Konflikten mit nginx-proxy kommt, das von Kubespray installiert wird. Möglicherweise benötigen Sie dies nicht.

Installieren Sie 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

Gehen wir zum Ceph-Datenspeicher, um dort einen separaten Benutzer zu erstellen. In der Dokumentation heißt es, dass der CephFS-Provisioner Cluster-Administrator-Zugriffsrechte benötigt. Wir werden jedoch einen separaten Benutzer erstellen fs mit eingeschränkten Rechten:

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 schauen wir uns gleich seinen Zugangsschlüssel an, wir werden ihn später brauchen:

ceph auth get-key client.fs

Lassen Sie uns separate Secret- und StorageClass-Klassen erstellen.
Nichts Neues, das haben wir bereits am Beispiel von RBD gesehen:

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-cephfs-secret
  namespace: ceph-csi-cephfs
stringData:
  # Необходимо для динамически создаваемых томов
  adminID: fs
  adminKey: <вывод предыдущей команды>

Anwenden des Manifests:

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: <cluster-id>

  # Имя файловой системы CephFS, в которой будет создан том
  fsName: cephfs

  # (необязательно) Пул Ceph, в котором будут храниться данные тома
  # pool: cephfs_data

  # (необязательно) Разделенные запятыми опции монтирования для Ceph-fuse
  # например:
  # fuseMountOptions: debug

  # (необязательно) Разделенные запятыми опции монтирования CephFS для ядра
  # См. man mount.ceph чтобы узнать список этих опций. Например:
  # kernelMountOptions: readdir_max_bytes=1048576,norbytes

  # Секреты должны содержать доступы для админа и/или юзера Ceph.
  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

  # (необязательно) Драйвер может использовать либо ceph-fuse (fuse), 
  # либо ceph kernelclient (kernel).
  # Если не указано, будет использоваться монтирование томов по умолчанию,
  # это определяется поиском ceph-fuse и mount.ceph
  # mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
  - debug

Füllen wir es hier aus Cluster-ID und anwendbar in Kubernetes:

kubectl apply -f storageclass.yaml

Проверка

Um dies zu überprüfen, erstellen wir wie im vorherigen Beispiel ein PVC:

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-cephfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  storageClassName: csi-cephfs-sc

Und prüfen Sie das Vorhandensein von PVC/PV:

kubectl get pvc
kubectl get pv

Wenn Sie sich Dateien und Verzeichnisse in CephFS ansehen möchten, können Sie dieses Dateisystem irgendwo mounten. Zum Beispiel wie unten gezeigt.

Gehen wir zu einem der Ceph-Clusterknoten und führen die folgenden Aktionen 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 die Montage von FS auf einem solchen Ceph-Knoten nur für Trainingszwecke geeignet, was wir auf unserem tun Slurm-Kurse. Ich glaube nicht, dass irgendjemand dies in der Produktion tun würde; es besteht ein hohes Risiko, versehentlich wichtige Dateien zu löschen.

Und zum Schluss schauen wir uns an, wie die Größenänderung von Volumes im Fall von CephFS funktioniert. Kehren wir zu Kubernetes zurück und bearbeiten unser Manifest für PVC – erhöhen Sie die Größe dort beispielsweise auf 7Gi.

Wenden wir die bearbeitete Datei an:

kubectl apply -f pvc.yaml

Schauen wir uns das bereitgestellte Verzeichnis an, um zu sehen, wie sich das Kontingent geändert hat:

getfattr -n ceph.quota.max_bytes <каталог-с-данными>

Damit dieser Befehl funktioniert, müssen Sie das Paket möglicherweise auf Ihrem System installieren attr.

Die Augen haben Angst und die Hände tun es

All diese Zaubersprüche und langen YAML-Manifeste scheinen auf den ersten Blick kompliziert zu sein, aber in der Praxis haben Slurm-Schüler den Dreh ziemlich schnell raus.
In diesem Artikel sind wir nicht tief in den Dschungel vorgedrungen – dafür gibt es eine offizielle Dokumentation. Wenn Sie sich für die Details zum Einrichten von Ceph-Speicher mit einem Kubernetes-Cluster interessieren, helfen Ihnen diese Links weiter:

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

Auf dem Slurm-Kurs Kubernetes-Basis Sie können noch einen Schritt weiter gehen und eine echte Anwendung in Kubernetes bereitstellen, die CephFS als Dateispeicher verwendet. Über GET/POST-Anfragen können Sie Dateien an Ceph übertragen und von Ceph empfangen.

Und wenn Sie mehr an Datenspeicherung interessiert sind, dann melden Sie sich an Neuer Kurs über Ceph. Während der Betatest läuft, ist der Kurs vergünstigt erhältlich und Sie können dessen Inhalte beeinflussen.

Autor des Artikels: Alexander Shvalov, praktizierender Ingenieur Southbridge, zertifizierter Kubernetes-Administrator, Autor und Entwickler von Slurm-Kursen.

Source: habr.com