Du Ceph dans mon Kubernetes

Posted by

Un cluster Ceph dans mon K8s

Make Stateful K8s Great Again

La semaine dernière, j’ai partagé mon sentiment sur le fait qu’il y a un intérêt à utiliser (dans certains cas) Kubernetes. Particulièrement dans le cas d’une infrastructure micro-services fortement hétérogène !

Cependant, certains pourraient être tentés de me faire remarquer que cette infrastructure logicielle a été conçue pour être stateless (l’ensemble des états étant stockés à part, dans une base de données externalisées). Et ainsi, elle s’intègre facilement dans Kubernetes (on se mord la queue).

C’est vrai, en partie. Kubernetes simplifie VRAIMENT la vie dans un contexte comme celui ci. Pour autant, ça ne veut pas dire non plus qu’il n’est pas possible (ni même complexe) de faire du stateful avec Kubernetes.

D’ailleurs, un de mes premiers articles sur Kube en parlait, puisque j’avais PoCé (PoCqué ? que c’est moche parfois le Franglais…) le stateful sur K8s avec XWiki, début 2018. Dans cet article, j’avais créé un instance XWiki + PostgreSQL avec du stockage hautement disponible via GlusterFS, installé directement SUR les machines K8s.

Et Ceph dans tout ça ?

Ceph, c’est une autre paire de manches. D’abord, c’est du stockage bloc en mode synchrone (alors que GlusterFS est un FS distribué). C’est donc pas du tout la même chose.

Thanks captain obvious

Ensuite, c’est quand même un poil plus compliqué à installer et configurer. GlusterFR on se contente d’un démon (ou deux) et de connecter les nœuds entre eux puis déclarer des briques. Sur Ceph, en revanche, il existe plusieurs notions complémentaires (les OSD, les moniteurs, les managers, …).

Une fois de plus, je ne dis pas que ça serait compliqué à faire dans K8s, mais bon… pourquoi s’embêter ?

Et donc Rook ?

Pourquoi s’embêter alors qu’un projet intégré à la CNCF prend en charge l’abstraction de Ceph (et d’autre) directement comme des ressources de Kubernetes ?

A Storage Orchestrator for Kubernetes Rook turns distributed storage systems into self-managing, self-scaling, self-healing storage services. It automates the tasks of a storage administrator: deployment, bootstrapping, configuration, provisioning, scaling, upgrading, migration, disaster recovery, monitoring, and resource management.

Grosso modo, Rook nous automatise la gestion de stockage hautement disponible, en gérant le stockage comme une ressource dans Kubernetes.

Dans ce tuto, je vous propose donc de se concentrer sur Ceph uniquement, mais vous pouvez très bien déployer autre chose (en suivant la doc).

Sachez que Ceph vient de passer en V1 dans le projet Rook, signe de stabilité. Cependant, vous avez plein d’autres options (Cassandra, Minio, …) à divers niveaux de maturité dans leur intégrations avec le projet Rook.

Prérequis

D’abord les prérequis => https://rook.github.io/docs/rook/v1.0/k8s-pre-reqs.html.

Rook est disponible depuis un moment, mais si vous voulez vous évité des soucis, il est conseillé de rester sur une version relativement récente de Kubernetes. Rook est officiellement supporté sur les K8s 1.10+.

Il vous faudra un compte avec les prévilèges cluster-admin pour bootstrapper Rook. Ne vous inquiétez pas, c’est juste le temps de créer les rôles et les CRDs.

Si vous n’en possédez pas, il est possible de demander à votre admin préféré de configurer directement les bons droits pour Rook à la main (https://rook.github.io/docs/rook/v1.0/psp.html).

Enfin, il sera nécessaire d’avoir sur les machines qui exécutent Rook+Ceph de disposer du module Kernel rbd et d’avoir le package lvm2 d’installé.

modprobe rbd

Ne doit rien retourner.

If it says ‘not found’, you may have to rebuild your kernel or choose a different Linux distribution.

On déploie Rook et Ceph !

Rook nous met à disposition des fichiers d’exemples sur le dépôt principal, notamment pour configurer Ceph de A à Z :

git clone https://github.com/rook/rook.git
cd rook/cluster/examples/kubernetes/ceph
kubectl create -f common.yaml
kubectl create -f operator.yaml
kubectl create -f cluster-test.yaml

Le fichier common.yaml va créer les CRD nécessaires à Rook, les (Cluster)Roles, les services accounts et enfin les (Cluster)RoleBindings associés.

Le fichier operator.yaml créé un déploiement rook-ceph-operator, qui va nous permettre de gérer les demandes de créations de CRD de Rook (lien vers un tuto pour expliquer ce que sont les CRD et les operators)

Le dernier fichier, cluster-test.yaml est celui qui va réellement créer le cluster Ceph dans votre Kubernetes. C’est lui qui va déterminer le nombre de chaque composant de Ceph dont vous aller disposer.

apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
  name: rook-ceph
  namespace: rook-ceph
spec:
  cephVersion:
    image: ceph/ceph:v14.2.2-20190722
    allowUnsupported: true
  dataDirHostPath: /var/lib/rook
  mon:
    count: 1
    allowMultiplePerNode: true
  dashboard:
    enabled: true
  monitoring:
    enabled: false  # requires Prometheus to be pre-installed
    rulesNamespace: rook-ceph
  network:
    hostNetwork: false
  rbdMirroring:
    workers: 0
  storage:
    useAllNodes: true
    useAllDevices: false
    directories:
    - path: /var/lib/rook

Note: Dans mon cas, j’ai ajouté à mes machines un disques /dev/sdd; j’ai donc remplacé les dernières lignes par "deviceFilter: sdd"

Une fois que vous avez exécuté la dernière commande, vous avez un cluster Ceph "de démo" opérationnel.

Il n’est pas conseillé de l’utiliser tel quel en production, car plusieurs composants ne sont pas redondés comme on a pu le voir en lisant le YAML ci dessus, et le stockage est assuré par un dossier sur chaque hôte Kubernetes, ce qui n’est pas du tout conseillé.

Cependant, on a l’ensemble des features qui sont activées, c’est parfait pour un test (mode bloc, objet ou fichier)

Vérifier que tout fonctionne

La documentation de Ceph recommande d’utiliser un déploiement appelé rook-toolbox pour vérifier que tout fonctionne.

Dans un premier temps, on peut commencer par simplement regarder si tous nos pods sont vivants :

kubectl --namespace=rook-ceph get pods
NAME                                                   READY   STATUS      RESTARTS   AGE
csi-cephfsplugin-5r648                                 2/2     Running     0          2d22h
csi-cephfsplugin-provisioner-0                         3/3     Running     0          2d22h
csi-rbdplugin-m7299                                    2/2     Running     0          2d22h
csi-rbdplugin-provisioner-0                            4/4     Running     0          2d22h
rook-ceph-agent-b79dl                                  1/1     Running     0          2d22h
rook-ceph-mgr-a-86586f9f4d-lz5df                       1/1     Running     0          2d22h
rook-ceph-mon-a-5fdc888bc4-qqb4m                       1/1     Running     0          2d22h
rook-ceph-operator-698b5d4fcc-dwdth                    1/1     Running     6          2d22h
rook-ceph-osd-0-667dcd84cf-h2tz8                       1/1     Running     0          2d22h
rook-ceph-osd-prepare-aks-agentpool-12737853-0-ntrn5   0/2     Completed   0          5h26m
rook-discover-sfdj4                                    1/1     Running     0          2d22h

Comme on peut le voir, tout est OK dans mon exemple.

On peut ensuite déployer la toolbox, dont le fichier YAML est présent dans le même dossier :

kubectl create -f toolbox.yaml

kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash

Une fois connecté, on peut lancer les commandes suivantes et commencer à interagir avec Ceph

ceph status
  cluster:
    id:     7099fc42-a47f-4412-8775-f6f3d4ce669d
    health: HEALTH_OK
 
  services:
    mon: 1 daemons, quorum a (age 111s)
    mgr: a(active, since 78s)
    osd: 1 osds: 1 up (since 60s), 1 in (since 60s)
 
  data:
    pools:   0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage:   12 GiB used, 84 GiB / 97 GiB avail
    pgs:   


ceph osd status
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+
| id |           host           |  used | avail | wr ops | wr data | rd ops | rd data |   state   |
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+
| 0  | aks-agentpool-12737853-0 | 12.4G | 84.4G |    0   |     0   |    0   |     0   | exists,up |
+----+--------------------------+-------+-------+--------+---------+--------+---------+-----------+

Créer un pool Ceph

Dans cet exemple, comme je n’ai qu’un seul OSD (un seul "disque", ici un dossier sur un serveur), je vais créer un pool sans réplication.

Si vous utilisez Rook en Production, vous aurez donc vous des disques dédiés (au minimum un sur tous les serveurs, ou à minima, au moins 3). Voir la documentation officielle pour plus d’info.

---
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
  name: replicapool
  namespace: rook-ceph
spec:
  failureDomain: host
  replicated:
    size: 1

De même, on va créer une StorageClass, qui va permettre à Kubernetes de réaliser la création des volumes à la demande (les PVs sont créés lorsqu’une application demande la création d’un volume via un Persistent Volume Claim)

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: rook-ceph-block
provisioner: ceph.rook.io/block
parameters:
  blockPool: replicapool
  clusterNamespace: rook-ceph
  fstype: xfs
reclaimPolicy: Retain

A partir de là, vous avez maintenant un stockage hautement disponible et réparti équitablement sur vos serveurs Kubernetes.

Si vous voulez tester, dans le même dépôt, on a à disposition 2 fichiers YAML d’exemple pour déployer MySQL + WordPress

zwindler:~/sources/rook/cluster/examples/kubernetes$ kubectl create -f mysql.yaml
service/wordpress-mysql created
persistentvolumeclaim/mysql-pv-claim created
deployment.apps/wordpress-mysql created

zwindler:~/sources/rook/cluster/examples/kubernetes$ kubectl get pvc
NAME             STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS      AGE
mysql-pv-claim   Bound    pvc-d245dd2d-d0a1-11e9-9f5c-26f444bf7bdc   20Gi       RWO            rook-ceph-block   10s

zwindler:~/sources/rook/cluster/examples/kubernetes$ kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                    STORAGECLASS      REASON   AGE
pvc-d245dd2d-d0a1-11e9-9f5c-26f444bf7bdc   20Gi       RWO            Retain           Bound    default/mysql-pv-claim   rook-ceph-block            26s

Elle est pas belle là vie :) ?

5 comments

  1. Je l’utilise depuis un moment et je trouve ça super comme système pour monter un FS hyperconvergé intégré à K8S.

    Merci pour cet article en français ! Ça permettra d’aider les « nouveaux » venus sur la solution :)

  2. Effectivement, ReadWriteMany n’est toujours pas supporté avec RDB. Par contre, CephFS lui l’est (mais du coup autant faire du Gluster, on est d’accord ;) ).

Leave a Reply

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.