Un exemple pratique de connexion d'un stockage basé sur Ceph à un cluster Kubernetes

Container Storage Interface (CSI) est une interface unifiée entre Kubernetes et les systèmes de stockage. Nous en avons déjà parlé brièvement dit, et aujourd'hui nous allons examiner de plus près la combinaison de CSI et Ceph : nous allons montrer comment connecter le stockage Ceph au cluster Kubernetes.
L'article fournit des exemples réels, quoique légèrement simplifiés, pour faciliter la perception. Nous n'envisageons pas d'installer et de configurer les clusters Ceph et Kubernetes.

Vous vous demandez comment ça marche ?

Un exemple pratique de connexion d'un stockage basé sur Ceph à un cluster Kubernetes

Ainsi, vous avez à portée de main un cluster Kubernetes, déployé par exemple, Kubespray. Il y a un cluster Ceph qui fonctionne à proximité - vous pouvez également l'installer, par exemple, avec ceci un ensemble de manuels de jeu. J'espère qu'il n'est pas nécessaire de mentionner que pour la production entre eux, il doit y avoir un réseau avec une bande passante d'au moins 10 Gbit/s.

Si vous avez tout cela, c'est parti !

Tout d'abord, allons sur l'un des nœuds du cluster Ceph et vérifions que tout est en ordre :

ceph health
ceph -s

Ensuite, nous allons immédiatement créer un pool pour les disques RBD :

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

Passons au cluster Kubernetes. Là, tout d’abord, nous installerons le pilote Ceph CSI pour RBD. Nous installerons, comme prévu, via Helm.
On ajoute un référentiel avec un graphique, on obtient un ensemble de variables pour le graphique ceph-csi-rbd :

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

Vous devez maintenant remplir le fichier cephrbd.yml. Pour ce faire, recherchez l'ID de cluster et les adresses IP des moniteurs dans Ceph :

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

Nous entrons les valeurs obtenues dans le fichier cephrbd.yml. Parallèlement, nous permettons la création de politiques PSP (Pod Security Policy). Options dans les sections plugin de nœud и fournisseur déjà dans le fichier, ils peuvent être corrigés comme indiqué ci-dessous :

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

Ensuite, il ne nous reste plus qu'à installer la charte dans le cluster Kubernetes.

helm upgrade -i ceph-csi-rbd ceph-csi/ceph-csi-rbd -f cephrbd.yml -n ceph-csi-rbd --create-namespace

Super, le pilote RBD fonctionne !
Créons une nouvelle StorageClass dans Kubernetes. Cela nécessite encore une fois un peu de bricolage avec Ceph.

Nous créons un nouvel utilisateur dans Ceph et lui donnons le droit d'écrire dans le pool Kube:

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

Voyons maintenant que la clé d'accès est toujours là :

ceph auth get-key client.rbdkube

La commande affichera quelque chose comme ceci :

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Ajoutons cette valeur à Secret dans le cluster Kubernetes - là où nous en avons besoin Clé utilisateur:

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

Et nous créons notre secret :

kubectl apply -f secret.yaml

Ensuite, nous avons besoin d’un manifeste StorageClass ressemblant à ceci :

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

Doit être rempli ID de cluster, ce que nous avons déjà appris par l'équipe céph fsidet appliquez ce manifeste au cluster Kubernetes :

kubectl apply -f storageclass.yaml

Pour vérifier comment les clusters fonctionnent ensemble, créons le PVC (Persistent Volume Claim) suivant :

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

Voyons immédiatement comment Kubernetes a créé le volume demandé dans Ceph :

kubectl get pvc
kubectl get pv

Tout semble génial ! A quoi cela ressemble-t-il du côté de Ceph ?
Nous obtenons une liste des volumes dans le pool et visualisons des informations sur notre volume :

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

Voyons maintenant comment fonctionne le redimensionnement d'un volume RBD.
Modifiez la taille du volume dans le manifeste pvc.yaml en 2Gi et appliquez-la :

kubectl apply -f pvc.yaml

Attendons que les modifications prennent effet et examinons à nouveau la taille du volume.

rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653

kubectl get pv
kubectl get pvc

On voit que la taille du PVC n'a pas changé. Pour savoir pourquoi, vous pouvez interroger Kubernetes pour obtenir une description YAML du PVC :

kubectl get pvc rbd-pvc -o yaml

Voici le problème :

message : En attente que l'utilisateur (re)démarre un pod pour terminer le redimensionnement du système de fichiers du volume sur le nœud. tapez : FileSystemResizePending

Autrement dit, le disque a grandi, mais pas le système de fichiers qu'il contient.
Pour développer le système de fichiers, vous devez monter le volume. Dans notre pays, le PVC/PV créé n’est actuellement utilisé d’aucune manière.

On peut créer un Pod de test, par exemple comme ceci :

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

Et maintenant regardons le PVC :

kubectl get pvc

La taille a changé, tout va bien.

Dans la première partie, nous avons travaillé avec le périphérique de bloc RBD (il signifie Rados Block Device), mais cela ne peut pas être fait si différents microservices doivent fonctionner simultanément avec ce disque. CephFS est bien mieux adapté pour travailler avec des fichiers plutôt qu'avec des images disque.
En utilisant l'exemple des clusters Ceph et Kubernetes, nous configurerons CSI et d'autres entités nécessaires pour fonctionner avec CephFS.

Obtenons les valeurs du nouveau graphique Helm dont nous avons besoin :

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

Encore une fois, vous devez remplir le fichier cephfs.yml. Comme auparavant, les commandes Ceph aideront à :

ceph fsid
ceph mon dump

Remplissez le fichier avec des valeurs comme celle-ci :

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

Veuillez noter que les adresses des moniteurs sont spécifiées sous la forme simple adresse:port. Pour monter des cephfs sur un nœud, ces adresses sont transférées au module noyau, qui ne sait pas encore fonctionner avec le protocole de surveillance v2.
Nous modifions le port pour httpMetrics (Prometheus y ira pour surveiller les métriques) afin qu'il n'entre pas en conflit avec nginx-proxy, qui est installé par Kubespray. Vous n’en aurez peut-être pas besoin.

Installez la charte Helm dans le cluster Kubernetes :

helm upgrade -i ceph-csi-cephfs ceph-csi/ceph-csi-cephfs -f cephfs.yml -n ceph-csi-cephfs --create-namespace

Allons au magasin de données Ceph pour y créer un utilisateur distinct. La documentation indique que le fournisseur CephFS nécessite des droits d'accès d'administrateur de cluster. Mais nous allons créer un utilisateur distinct fs avec des droits limités :

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'

Et regardons tout de suite sa clé d’accès, nous en aurons besoin plus tard :

ceph auth get-key client.fs

Créons des Secret et StorageClass séparés.
Rien de nouveau, nous l’avons déjà vu dans l’exemple du RBD :

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

Application du manifeste :

kubectl apply -f secret.yaml

Et maintenant - une StorageClass distincte :

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

Remplissons-le ici ID de cluster et applicable dans Kubernetes :

kubectl apply -f storageclass.yaml

Проверка

Pour vérifier, comme dans l'exemple précédent, créons un PVC :

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

Et vérifiez la présence de PVC/PV :

kubectl get pvc
kubectl get pv

Si vous souhaitez consulter des fichiers et des répertoires dans CephFS, vous pouvez monter ce système de fichiers quelque part. Par exemple, comme indiqué ci-dessous.

Allons sur l'un des nœuds du cluster Ceph et effectuons les actions suivantes :

# Точка монтирования
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

Bien entendu, monter FS sur un nœud Ceph comme celui-ci ne convient qu'à des fins de formation, ce que nous faisons sur notre Cours Slurm. Je ne pense pas que quiconque ferait cela en production ; il existe un risque élevé d’effacement accidentel de fichiers importants.

Et enfin, vérifions comment les choses fonctionnent avec le redimensionnement des volumes dans le cas de CephFS. Revenons à Kubernetes et modifions notre manifeste pour PVC - augmentez-y la taille, par exemple, à 7Gi.

Appliquons le fichier édité :

kubectl apply -f pvc.yaml

Regardons le répertoire monté pour voir comment le quota a changé :

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

Pour que cette commande fonctionne, vous devrez peut-être installer le package sur votre système attribut.

Les yeux ont peur, et les mains font

Tous ces sorts et ces longs manifestes YAML semblent compliqués en apparence, mais en pratique, les étudiants de Slurm les maîtrisent assez rapidement.
Dans cet article, nous ne sommes pas allés au fond de la jungle - il existe une documentation officielle à ce sujet. Si vous êtes intéressé par les détails de la configuration du stockage Ceph avec un cluster Kubernetes, ces liens vous aideront :

Principes généraux de Kubernetes travaillant avec des volumes
Documentation RBD
Intégration de RBD et Kubernetes du point de vue de Ceph
Intégrer RBD et Kubernetes du point de vue de CSI
Documentation générale CephFS
Intégration de CephFS et Kubernetes du point de vue de CSI

Sur le parcours Slurm Base Kubernetes vous pouvez aller un peu plus loin et déployer une vraie application dans Kubernetes qui utilisera CephFS comme stockage de fichiers. Grâce aux requêtes GET/POST, vous pourrez transférer des fichiers vers et les recevoir de Ceph.

Et si vous êtes plus intéressé par le stockage de données, inscrivez-vous à nouveau cours sur Ceph. Pendant que le test bêta est en cours, le cours peut être obtenu à prix réduit et vous pouvez influencer son contenu.

Auteur de l'article : Alexander Shvalov, ingénieur en exercice Southbridge, Administrateur Kubernetes certifié, auteur et développeur de cours Slurm.

Source: habr.com