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
- Documentation Rook 1.19 : rook.io/docs/v1.19
- Quickstart Rook-Ceph : rook.io/quickstart
- Documentation Ceph Squid : docs.ceph.com/squid
- Charts Helm Rook : artifacthub.io/rook-ceph
- CephObjectStore et S3 : rook.io/object-storage
- Spec CRD CephCluster : rook.io/ceph-cluster-crd
É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.