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 :) ?
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 :)
Avec plaisir !
J’écris justement ce blog pour fournir des ressources en Français sur ce genre de sujets :)
Ok… Petit souci par contre, si c’est rdb alors il est impossible d’avoir du write many. Raison pour laquelle je reste sur gluster + heketi. Mais très bon article.
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 ;) ).
Bonjour,
et un grand merdci pour vos tutos je suis fan
je rencontre sur erreur lors du déploiement une idée ? suis en ubuntu 18.04 K8S 14.2
root@cephk8master:~/rook/cluster/examples/kubernetes/ceph# kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l « app=rook-ceph-tools » -o jsonpath='{.items[0].metadata.name}’) bash
bash: warning: setlocale: LC_CTYPE: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_COLLATE: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_MESSAGES: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_NUMERIC: cannot change locale (en_US.UTF-8): No such file or directory
bash: warning: setlocale: LC_TIME: cannot change locale (en_US.UTF-8): No such file or directory
[root@rook-ceph-tools-7f9b9bfdb4-j47ml /]# ceph status
unable to get monitor info from DNS SRV with service name: ceph-mon
[errno 2] error connecting to the cluster
[root@rook-ceph-tools-7f9b9bfdb4-j47ml /]#