Rook via Ceph n'approvisionne pas mes Persistent Volume Claims !

Rook via Ceph n'approvisionne pas mes Persistent Volume Claims !

By CHOJNOWSKI Eyal

9 sept. 2019

Catégories : DevOps & SRE | Tags : Kubernetes, PVC, Linux, Rook, Ubuntu, Ceph

L’installation de Ceph dans un cluster Kubernetes peut être automatisé par l’utilisation de Rook. Actuellement en stage chez Adaltas, j’étais en charge de participer à la configuration d’un cluster Kubernetes (k8s). Pour éviter de casser quelque chose sur notre cluster production, nous avons décidé de faire nos expérimentations via l’installation d’un cluster k8s sur 3 machines virtuelles (un nœud maître n1, deux nœuds esclaves n2 et n3) en utilisant Vagrant avec VirtualBox sur le backend et Ubuntu 18.10 en tant qu’OS.

Lors de l’installation du cluster de test, nous avons rencontré un problème avec Rook en utilisant Ceph qui l’empêche d’approvisionner les Persistent Volume Claim (PVC). Cet article détaille comment effectuer une installation de base de Rook avec Ceph sur les machines virtuelles, le problème rencontré et comment le résoudre. Mais d’abord …

… un rappel rapide à propos du rôle des PVCs !

Lorsqu’un pod doit stocker diverses données (journaux ou métriques, par exemple) de manière persitante, elle doit décrire le type de stockage dont elle a besoin (taille, performance, …) dans un PVC. Le cluster fournira ensuite un Persistent Volume (PV) s’il correspond aux exigences du PVC. Le PV peut : soit être approvisionné statiquement si un administrateur a créé manuellement un PV correspondant, soit être approvisionné dynamiquement. La création manuelle de PVs peut être fastidieuses si beaucoup d’entre eux sont nécessaires aux pods, c’est pourquoi il est intéressant pour le cluster de pouvoir les approvisionner dynamiquement. Pour rendre le cluster capable de fournir de manière dynamique un PV, le PVC doit indiquer la Storage Class qu’il veut utiliser. Si une telle Storage Class est disponible sur le cluster, un PV sera fourni dynamiquement au pod.

Voici quelques liens que vous pouvez suivre si vous voulez en savoir à propos des PVCs, PVs et Storage Classes :

Installer Rook sur votre cluster k8s

L’installation d’un cluster k8s n’entrant pas dans le cadre de cet article, je vais supposer que vous avez déjà un cluster k8s opérationnel. Si ce n’est pas le cas, vous pouvez facilement trouver de la documentation sur internet afin de bootstraper rapidement un cluster k8s.

Le processus d’installation de Rook n’est pas compliqué, il suffit d’appliquer quelques manifestes. Première étape, clonez le repo git de Rook :

git clone https://github.com/rook/rook 

Puis passez au dernier tag de version (qui est v1.0.1 au moment de l’écriture de cet article) en utilisant :

git checkout v1.0.1

Les fichiers d’intérêts (qui sont listés ci-dessous) se trouve dans le dossier cluster/examples/kubernetes/ceph.

  1. common.yaml
  2. operator.yaml
  3. cluster.yaml
  4. storageclass.yaml

Appliquer chacuns d’entres eux dans l’ordre dans lequel ils sont listés avec :

kubectl apply -f <file.yaml>

La dernière étape est de définir la resources storageclass, inscrite dans le fichier storageclass.yaml que nous venons d’appliquer, comme storageclass par défaut dans notre cluster. Pour ce faire, exécutez la commande suivante :

kubectl patch storageclass rook-ceph-block \
  -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

Le problème

Le cluster Rook prendra un certain temps à se déployer, le temps de télécharger les images nécessaires et de déployer les pods. Après quelques minutes, la sortie de kubectl get pods -n rook-ceph devrait ressembler à celle-ci :

NAME                                           READY   STATUS      RESTARTS   AGE
rook-ceph-agent-8zv7p                          1/1     Running     0          4m8s
rook-ceph-agent-ghwgl                          1/1     Running     0          4m8s
rook-ceph-mgr-a-6d8cf6d5d7-txnrj               1/1     Running     0          102s
rook-ceph-mon-a-588475cbdb-htt4h               1/1     Running     0          2m55s
rook-ceph-mon-b-5b7cdc894f-q6wwr               1/1     Running     0          2m47s
rook-ceph-mon-c-846fc479cb-96sjq               1/1     Running     0          119s
rook-ceph-operator-765ff54667-q5qk4            1/1     Running     0          4m43s
rook-ceph-osd-prepare-n2.k8s.test-d4p9w        0/2     Completed   0          80s
rook-ceph-osd-prepare-n3.k8s.test-lrkbc        0/2     Completed   0          80s
rook-discover-hxxtl                            1/1     Running     0          4m8s
rook-discover-mmdl5                            1/1     Running     0          4m8s

Comme nous pouvons le voir ici, il existe deux modules appelés rook-ceph-osd-prepare... pour lesquels le statut est “Terminé”. Nous nous attendions à voir apparaitre des pods OSD (Object Storage Device) une fois le statut des modules rook-ceph-osd-prepare ... terminés mais ce n’est pas le cas ici. Les pods OSD n’apparaissant pas, ce qui signifie que les futures PVC ne seront pas approvisionnés par Rook et resteront en attente. Nous pouvons voir un exemple de ce problème lorsque nous essayons de déployer une instance Gitlab avec Helm. Voici le résultat de kubectl get pvc -n gitlab :

NAME                        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS      AGE
gitlab-minio                Pending                                      rook-ceph-block   6m7s
gitlab-postgresql           Pending                                      rook-ceph-block   6m7s
gitlab-prometheus-server    Pending                                      rook-ceph-block   6m7s
gitlab-redis                Pending                                      rook-ceph-block   6m7s
repo-data-gitlab-gitaly-0   Pending                                      rook-ceph-block   6m6s

Nous pouvons voir qu’aucun PVC n’est approvisionné quand bien même ils ont été assigné la bonne Storage Class.

La solution

Après quelques recherches, nous avons découvert qu’en fait, pour que Rook fonctionne, nous avons besoin d’avoir un périphérique de stockage dédié qu’il peut utiliser pour stocker les PVs. Pour résoudre ce problème, nous avions besoin dans notre cas d’ajouter un nouveau disque virtuel à nos machines virtuelles via le fichier VagrantFile.

Pour créer et attacher un nouveau disque virtuel à une machine virtuelle VirtualBox, nous devons utiliser la commande vboxmanage, ou nous pouvons plus facilement le définir directement dans le VagrantFile, comme dans cet extrait :

#[...]
  config.vm.define :n2 do |node|
    node.vm.box = box
    node.vm.hostname = "n2"
    node.vm.network :private_network, ip: "10.10.10.53"
    node.vm.provider "virtualbox" do |d|
      d.customize ["modifyvm", :id, "--memory", 4096]
      d.customize ["modifyvm", :id, "--cpus", 2]
      d.customize ["modifyvm", :id, "--ioapic", "on"]

      # Creating a virtual disk called "disk_osd-n2" with a size of 125GB
      d.customize ["createhd", "--filename", "disk_osd-n2", "--size", 125 * 1024]

      # Attaching the newly created virtual disk to our node
      d.customize ["storageattach", :id, "--storagectl", "SCSI", "--port", 3, "--device", 0, "--type", "hdd", "--medium", "disk_osd-n2.vdi"] 
    end
  end
#[...]

Si nous lançons une nouvelle fois l’installation dans son ensenble, nous pouvons voir que les pods OSD apparaissent :

NAME                                           READY   STATUS      RESTARTS   AGE
rook-ceph-agent-gs4sn                          1/1     Running     0          3m55s
rook-ceph-agent-hwrrf                          1/1     Running     0          3m55s
rook-ceph-mgr-a-dbdffd588-v2x2b                1/1     Running     0          75s
rook-ceph-mon-a-f5d5d4654-nmk6j                1/1     Running     0          2m28s
rook-ceph-mon-b-6c98476587-jq2s5               1/1     Running     0          104s
rook-ceph-mon-c-6f9f7f5bd6-8r8qw               1/1     Running     0          91s
rook-ceph-operator-765ff54667-vqj4p            1/1     Running     0          4m29s
rook-ceph-osd-0-5cf569ddf5-rw827               1/1     Running     0          28s   <== Ici!
rook-ceph-osd-1-7577f777f9-vjxml               1/1     Running     0          22s   <== Et ici
rook-ceph-osd-prepare-n2.k8s.test-bdw2g        0/2     Completed   0          51s
rook-ceph-osd-prepare-n3.k8s.test-26d86        0/2     Completed   0          51s
rook-discover-mblm6                            1/1     Running     0          3m55s
rook-discover-wsk2z                            1/1     Running     0          3m55s

Et si nous vérifions le PVC créé par l’installation faite par Helm de Gitlab :

NAME                        STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
gitlab-minio                Bound    pvc-5f32d9f5-7d76-11e9-b3fe-02897c39bcfa   10Gi       RWO            rook-ceph-block   19s
gitlab-postgresql           Bound    pvc-5f342615-7d76-11e9-b3fe-02897c39bcfa   8Gi        RWO            rook-ceph-block   19s
gitlab-prometheus-server    Bound    pvc-5f34feb5-7d76-11e9-b3fe-02897c39bcfa   8Gi        RWO            rook-ceph-block   19s
gitlab-redis                Bound    pvc-5f3a0d3d-7d76-11e9-b3fe-02897c39bcfa   5Gi        RWO            rook-ceph-block   19s
repo-data-gitlab-gitaly-0   Bound    pvc-5fe63ad2-7d76-11e9-b3fe-02897c39bcfa   50Gi       RWO            rook-ceph-block   17s

Les PVCs sont enfin approvisionné !

Un peu plus loin, customiser cluster.yaml

Vous avez peut-être remarqué que nous n’avons donné aucune information à Rook sur la façon de procéder afin de trouver un périphérique approprié à utiliser pour le stockage ; il le détecte juste de manière autonome celui que nous avons attaché à la machine virtuelle et l’a utilisé. Pour beaucoup de raisons évidentes, ce n’est certainement pas un comportement souhaité étant donné que dans contexte réel, nous pourrions avoir nombreux dispositifs connectés ayant un but différent de celui de simplement fournir du stockage à Rook. Il est bien sûr possible de personnaliser la façon dont il trouve et utilise le stockage. Tout est défini dans le manifeste cluster.yaml. Les catégorie associé du manifeste est storage. Voici la configuration par défaut :

storage:
  useAllNodes: true
  useAllDevices: true # <==
  deviceFilter:
  location:
  config:

Le champ useAllDevices a la valeur true. Depuis la documentation officielle de Rook : il indique “si tous les périphériques trouvés sur les nœuds du cluster doivent être automatiquement consommé par OSDs”. La solution consiste à indiquer à Rook où regarder au lieu de sélectionner automatiquement tout périphérique disponible. Si nous mettons useAllDevices à false, nous pouvons utiliser les champs suivants :

  1. deviceFilter pour définir un filtre regex ; par exemple ^sd[a-d] pour trouver un disque commençant par “sd” puis suivis par a, b, c ou d,
  2. devices pour définir une liste de disques individuel qui pourront être utilisés,
  3. directories pour définir une liste de répertoires qui seront utilisés comme espace de stockage pour le cluster.

Il est aussi possible de définir une configuration par node en réglant useAllNodes à false, mais cela sort du cadre de cet article. Si vous voulez en apprendre plus à propos de la configuration du stockage pour Rook, vous pouvez jeter un œil à la documention.

The end

Merci d’avoir lu cet article, j’espère qu’il vous aura apporté un peu de lumière si vous étiez confronté au même problème !

Canada - Morocco - France

International locations

10 rue de la Kasbah
2393 Rabbat
Canada

Nous sommes une équipe passionnées par l'Open Source, le Big Data et les technologies associées telles que le Cloud, le Data Engineering, la Data Sciencem le DevOps…

Nous fournissons à nos clients un savoir faire reconnu sur la manière d'utiliser les technologies pour convertir leurs cas d'usage en projets exploités en production, sur la façon de réduire les coûts et d'accélérer les livraisons de nouvelles fonctionnalités.

Si vous appréciez la qualité de nos publications, nous vous invitons à nous contacter en vue de coopérer ensemble.