Self-hosting

Stockage persistant avec Rook-Ceph sur Kubernetes pas-à-pas

13 دقائق للقراءة

Article principal · Ce tutoriel fait partie de la série Kubernetes domestique sur Proxmox VE. Tutoriel précédent : Cilium CNI eBPF. Tutoriel suivant : Argo CD GitOps.

Sans stockage persistant, un cluster Kubernetes ne peut faire tourner que des charges sans état : on perd toutes les données dès qu un pod redémarre. Pour héberger une base PostgreSQL, un Vaultwarden, un Nextcloud ou un MinIO, il faut un fournisseur CSI (Container Storage Interface) qui produise des volumes persistants à la demande. Rook est un opérateur Kubernetes qui orchestre Ceph — un stockage distribué de classe entreprise — directement à l intérieur du cluster, sur les disques des workers. La version 1.19.5 sortie au printemps 2026 supporte Ceph Squid 19.2.0+ et Kubernetes 1.30 minimum. Ce tutoriel installe Rook 1.19, déploie un cluster Ceph à trois OSD, expose une StorageClass de blocs RBD, un système de fichiers CephFS partagé et un bucket S3 ObjectStore.

Étape 1 — Préparer les disques sur les workers

Ceph exige des disques dédiés, sans système de fichiers ni partition existante. Sur les trois workers Talos, on a ajouté au tutoriel précédent un second disque de 32 Gio (/dev/sdb). Vérifier que ces disques sont vierges depuis le poste de travail.

for ip in 192.168.1.71 192.168.1.72 192.168.1.73; do
  echo "=== Worker $ip ==="
  talosctl -n $ip get disks
done
# La sortie doit lister sda (32 Gio, système Talos) et sdb (32 Gio, vide)

Si sdb apparaît avec des partitions résiduelles d un test précédent, l effacer proprement avant que Rook l adopte. La commande wipefs n existe pas sur Talos parce qu il n y a pas de shell, mais Rook le fera automatiquement avec son CRD CephCluster.spec.storage.useAllDevices=true à condition que le disque soit non-monté.

Étape 2 — Installer l opérateur Rook

L opérateur Rook s installe via Helm depuis le dépôt officiel. C est le contrôleur qui interprète les CRD CephCluster, CephBlockPool, CephFilesystem et CephObjectStore.

helm repo add rook-release https://charts.rook.io/release
helm repo update

kubectl create namespace rook-ceph

helm install rook-ceph rook-release/rook-ceph \
  --version v1.19.5 \
  --namespace rook-ceph \
  --set crds.enabled=true \
  --set monitoring.enabled=true \
  --set csi.enableRBDDriver=true \
  --set csi.enableCephFSDriver=true

Helm crée les CRD, le déploiement rook-ceph-operator, les comptes RBAC nécessaires. Vérifier que l opérateur est en Running avant de continuer : kubectl get pods -n rook-ceph -w. Compter une à deux minutes. Si le pod boucle en CrashLoopBackOff, inspecter les logs ; la cause typique est une CRD préexistante d une ancienne installation.

Étape 3 — Déclarer le cluster Ceph

Le cluster Ceph se déclare via une CRD CephCluster. Le manifest ci-dessous déploie trois moniteurs (un par worker), trois managers, et adopte automatiquement les disques disponibles.

apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
  name: rook-ceph
  namespace: rook-ceph
spec:
  cephVersion:
    image: quay.io/ceph/ceph:v19.2.3
    allowUnsupported: false
  dataDirHostPath: /var/lib/rook
  skipUpgradeChecks: false
  mon:
    count: 3
    allowMultiplePerNode: false
  mgr:
    count: 2
    modules:
    - name: pg_autoscaler
      enabled: true
  dashboard:
    enabled: true
    ssl: true
  monitoring:
    enabled: true
  storage:
    useAllNodes: false
    useAllDevices: false
    nodes:
    - name: talos-wk-1
      devices:
      - name: sdb
    - name: talos-wk-2
      devices:
      - name: sdb
    - name: talos-wk-3
      devices:
      - name: sdb
kubectl apply -f cephcluster.yaml

# Suivre le démarrage (5 à 10 minutes)
kubectl -n rook-ceph get cephcluster -w
# Phase doit progresser : Creating → Failing → Connecting → Ready

Quand la phase indique Ready, Ceph est opérationnel. Trois pods rook-ceph-mon, deux rook-ceph-mgr et trois rook-ceph-osd doivent être en Running. Si un OSD ne démarre pas, vérifier que le disque cible existe bien sur le worker correspondant et qu il est libre.

Étape 4 — Inspecter la santé du cluster Ceph

Rook expose un pod toolbox équipé du client Ceph CLI. C est l outil de diagnostic principal pour comprendre ce qui se passe au niveau du cluster Ceph lui-même.

kubectl apply -f \
  https://raw.githubusercontent.com/rook/rook/v1.19.5/deploy/examples/toolbox.yaml

kubectl -n rook-ceph exec -it deploy/rook-ceph-tools -- ceph status
# La sortie doit indiquer health: HEALTH_OK et 3 osds up

Voir HEALTH_OK avec trois OSD up et trois moniteurs in quorum confirme que le cluster Ceph est sain. HEALTH_WARN est acceptable temporairement (PGs en cours de placement par exemple), mais ne doit pas persister plus de quelques minutes après l installation.

Étape 5 — Créer une StorageClass blocs RBD

RBD (RADOS Block Device) est le format de blocs Ceph, équivalent d un disque virtuel attaché à un pod. C est le mode de stockage le plus utilisé pour les bases de données et les charges nécessitant un accès ReadWriteOnce.

apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
  name: replicapool
  namespace: rook-ceph
spec:
  failureDomain: host
  replicated:
    size: 3
    requireSafeReplicaSize: true
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: rook-ceph-block
  annotations:
    storageclass.kubernetes.io/is-default-class: "true"
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
  clusterID: rook-ceph
  pool: replicapool
  imageFormat: "2"
  imageFeatures: layering
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-rbd-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-rbd-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
  csi.storage.k8s.io/fstype: ext4
allowVolumeExpansion: true
reclaimPolicy: Delete
kubectl apply -f cephblockpool.yaml

kubectl get sc
# rook-ceph-block doit apparaître marqué "(default)"

La StorageClass rook-ceph-block est déclarée par défaut : tout PVC créé sans storageClassName explicite l utilisera. La réplication x3 garantit qu un volume reste accessible même si un worker tombe (ce qui sera testé plus loin).

Étape 6 — Tester le provisionnement d un volume

Le test classique consiste à créer un PVC, déployer un pod qui l utilise, écrire un fichier, supprimer le pod, le recréer, et vérifier que le fichier persiste.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: test-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: test-pod
spec:
  containers:
  - name: app
    image: busybox
    command: ["sh", "-c", "echo persistent-data > /data/hello.txt && sleep 3600"]
    volumeMounts:
    - name: data
      mountPath: /data
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: test-pvc
kubectl apply -f test-pvc.yaml

# Vérifier que le PVC est lié à un PV
kubectl get pvc test-pvc
# STATUS doit être Bound après quelques secondes

# Lire le fichier
kubectl exec test-pod -- cat /data/hello.txt
# Doit afficher : persistent-data

# Détruire le pod et le recréer
kubectl delete pod test-pod
kubectl apply -f test-pvc.yaml

kubectl exec test-pod -- cat /data/hello.txt
# Doit toujours afficher : persistent-data

Le fichier qui survit à la destruction du pod confirme que le volume RBD est bien provisionné, monté et persistant. C est la preuve de concept minimale qui valide la chaîne CSI complète.

Étape 7 — Activer CephFS pour le partage de fichiers

Pour les charges qui nécessitent un accès ReadWriteMany (Nextcloud, WordPress multi-instance), CephFS fournit un système de fichiers partagé. Il s active via une CRD CephFilesystem et une StorageClass dédiée.

apiVersion: ceph.rook.io/v1
kind: CephFilesystem
metadata:
  name: myfs
  namespace: rook-ceph
spec:
  metadataPool:
    failureDomain: host
    replicated:
      size: 3
  dataPools:
  - name: data0
    failureDomain: host
    replicated:
      size: 3
  metadataServer:
    activeCount: 1
    activeStandby: true
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: rook-cephfs
provisioner: rook-ceph.cephfs.csi.ceph.com
parameters:
  clusterID: rook-ceph
  fsName: myfs
  pool: myfs-data0
  csi.storage.k8s.io/provisioner-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
  csi.storage.k8s.io/controller-expand-secret-name: rook-csi-cephfs-provisioner
  csi.storage.k8s.io/controller-expand-secret-namespace: rook-ceph
  csi.storage.k8s.io/node-stage-secret-name: rook-csi-cephfs-node
  csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
allowVolumeExpansion: true
reclaimPolicy: Delete

Après kubectl apply, la StorageClass rook-cephfs permet de créer des PVC en mode RWX. Plusieurs pods sur des nœuds différents peuvent monter le même volume simultanément, ce qui n est pas possible avec RBD.

Étape 8 — Exposer un bucket S3 compatible avec ObjectStore

Ceph fournit un service S3-compatible via RGW (RADOS Gateway). C est extrêmement utile pour héberger les artefacts de build, les sauvegardes Velero, ou les médias d une application web.

apiVersion: ceph.rook.io/v1
kind: CephObjectStore
metadata:
  name: my-store
  namespace: rook-ceph
spec:
  metadataPool:
    failureDomain: host
    replicated:
      size: 3
  dataPool:
    failureDomain: host
    erasureCoded:
      dataChunks: 2
      codingChunks: 1
  preservePoolsOnDelete: false
  gateway:
    port: 80
    instances: 1
# Note : EC k=2 m=1 est le minimum requis pour 3 hôtes en failure domain host. La perte d'un hôte épuise la redondance. Pour un homelab sérieux, prévoir 4 hôtes (k+m+1) ou bascule en replicated x3 si le surcoût d'espace est acceptable.
kubectl apply -f cephobjectstore.yaml

# Créer un user S3 (génère access_key et secret_key)
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- \
  radosgw-admin user create --uid=homelab --display-name="Homelab User"
# Noter access_key et secret_key dans la sortie

L endpoint S3 est accessible via le service rook-ceph-rgw-my-store. Pour y accéder depuis l extérieur, on créera un Ingress dans le tutoriel observabilité. Pour les tests immédiats, un port-forward suffit.

Étape 9 — Tester la résilience à la perte d un OSD

L intérêt d un stockage répliqué se mesure quand un disque ou un nœud tombe. On éteint brutalement un worker pour valider que les volumes restent accessibles.

# Sur Proxmox, éteindre un worker
qm stop 1101

# Depuis le poste, observer Ceph
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph status
# health passe en HEALTH_WARN, 1 OSD down, mais le cluster reste fonctionnel

# Vérifier qu un PVC reste utilisable
kubectl exec test-pod -- cat /data/hello.txt
# Doit toujours afficher : persistent-data

# Redémarrer le worker
qm start 1101
sleep 60
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph status
# health revient à HEALTH_OK après quelques minutes (recovery automatique)

Le fichier hello.txt qui reste lisible alors qu un tiers du stockage est offline démontre la valeur réelle de Rook-Ceph : un homelab survit à une panne matérielle sans intervention humaine. C est ce qu on n a pas avec local-path-provisioner ou NFS sur un seul serveur.

Erreurs fréquentes et résolutions

Symptôme Cause Résolution
Les OSD restent en Pending Disques déjà partitionnés ou montés Effacer les disques (sur Talos via reset complet du nœud) ou changer de disque cible
health: HEALTH_WARN persistant après installation Trop peu de PGs ou PG en cours de placement Activer pg_autoscaler et patienter ; sinon ajuster osd_pool_default_pg_num
PVC restent en Pending StorageClass non marquée par défaut, ou provisionner CSI down Vérifier kubectl get sc et les pods csi-rbdplugin-provisioner
Les pods avec PVC ne démarrent pas après reboot du nœud Verrou RBD non libéré côté Ceph rbd lock list et rbd lock remove via la toolbox
Performance dégradée après ajout d OSD Rebalancing en cours, normal Patienter ou ralentir le rebalance avec osd_max_backfills=1

Pour la suite du parcours

Le stockage persistant est en place : blocs RBD pour les bases de données, CephFS pour le partage, ObjectStore pour S3. Toute charge déployée à partir de maintenant pourra demander des volumes durables. La prochaine étape consiste à automatiser le déploiement de ces charges via GitOps. Le tutoriel Bootstrap GitOps avec Argo CD sur Kubernetes détaille la mise en place d Argo CD 3.4 et la structure du dépôt Git associé. Pour la vue d ensemble, retourner au guide principal Kubernetes domestique sur Proxmox VE.

Ressources et documentation officielle

Étape 10 — Activer le dashboard Ceph et l accès via Ingress

Le dashboard Ceph fournit une interface web qui montre la santé du cluster, l usage par pool, les performances par OSD, et les alertes en cours. Il est activé dans la CRD CephCluster (champ dashboard.enabled: true) mais n est pas exposé hors du cluster par défaut. On crée un Ingress avec cert-manager pour y accéder en HTTPS via un nom DNS local.

# Récupérer le mot de passe admin du dashboard
kubectl -n rook-ceph get secret rook-ceph-dashboard-password \
  -o jsonpath="{['data']['password']}" | base64 --decode
# Ce mot de passe permet l accès initial, à changer immédiatement après login

# Créer un Service ClusterIP exposant le dashboard
kubectl -n rook-ceph patch service rook-ceph-mgr-dashboard \
  --type='merge' -p '{"spec":{"type":"ClusterIP"}}'

L Ingress associé pointera ensuite vers ce service sur le port 8443. La configuration cert-manager pour Let s Encrypt sera détaillée dans le tutoriel observabilité, qui s applique aussi bien à Grafana qu au dashboard Ceph. Une fois en place, l URL https://ceph.lan ouvre l interface complète.

Étape 11 — Comprendre la consommation et planifier la croissance

Le facteur de réplication 3 utilisé jusqu ici signifie que chaque octet utile occupe trois octets sur disque. Avec trois OSD de 32 Gio, l espace utile total est donc d environ 30 Gio (en tenant compte de l espace système Ceph). Pour passer à 100 Gio utilisables, il faut soit ajouter trois OSD supplémentaires de 32 Gio (un par worker), soit remplacer les disques par des disques plus gros.

L ajout d un OSD se fait en éditant la CRD CephCluster pour y déclarer le nouveau disque. Rook démarre automatiquement un nouveau pod OSD et lance le rebalancing : Ceph redistribue les données pour que la charge soit uniforme entre tous les OSD. Le rebalancing est transparent pour les charges utiles ; il consomme simplement du débit réseau et CPU pendant quelques minutes à quelques heures selon le volume.

# Surveiller le rebalancing depuis la toolbox
kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph status
# misplaced objects descend progressivement vers 0

kubectl -n rook-ceph exec deploy/rook-ceph-tools -- ceph osd df
# Affiche l usage par OSD : doit converger vers une distribution uniforme

Une distribution uniforme sur tous les OSD confirme que le rebalancing est terminé et que le cluster utilise pleinement la capacité ajoutée. Pour une croissance importante (> 50 % de capacité ajoutée), il vaut mieux étaler l ajout sur plusieurs jours pour ne pas saturer le réseau pendant le rebalancing.

Étape 12 — Sauvegarder la configuration Ceph

Comme pour Cilium, la configuration Rook-Ceph doit être versionnée pour permettre une reconstruction. Les CRD CephCluster, CephBlockPool, CephFilesystem, CephObjectStore et les StorageClass associées sont à exporter et à committer dans le dépôt Git d Argo CD (tutoriel suivant). Les secrets générés par Rook (admin keyring, dashboard password) restent dans le cluster ; en cas de reconstruction, Rook en génère de nouveaux.

mkdir -p homelab-gitops/storage
kubectl -n rook-ceph get cephcluster rook-ceph -o yaml > homelab-gitops/storage/cephcluster.yaml
kubectl -n rook-ceph get cephblockpool replicapool -o yaml > homelab-gitops/storage/cephblockpool.yaml
kubectl -n rook-ceph get cephfilesystem myfs -o yaml > homelab-gitops/storage/cephfilesystem.yaml
kubectl -n rook-ceph get cephobjectstore my-store -o yaml > homelab-gitops/storage/cephobjectstore.yaml
kubectl get sc rook-ceph-block rook-cephfs -o yaml > homelab-gitops/storage/storageclasses.yaml

cd homelab-gitops
git add storage/
git commit -m "Initial Rook-Ceph configuration"

Voir les six fichiers ajoutés à la racine du dépôt et le commit créé permet de reconstruire la configuration Ceph en moins de cinq minutes sur un nouveau cluster, à condition d avoir des disques disponibles. C est la base de la résilience opérationnelle : la configuration vit dans Git, le cluster ne fait qu en réaliser une copie.

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité