TopoLVM est un CSI driver Kubernetes qui provisionne des volumes locaux en utilisant LVM (Logical Volume Manager) sur les nœuds. Contrairement aux solutions distribuées comme Longhorn ou Rook/Ceph, TopoLVM n'effectue aucune réplication réseau - les données restent sur les disques locaux du nœud, ce qui donne des performances maximales (accès NVMe direct, pas de saut réseau).
Sa fonctionnalité clé est le scheduling capacity-aware : TopoLVM expose la capacité LVM disponible sur chaque nœud au scheduler Kubernetes, qui peut alors placer les pods sur les nœuds ayant suffisamment d'espace. Cette fonctionnalité manque aux provisioners locaux standards de Kubernetes. Développé par Cybozu (Japon), il est projet CNCF Sandbox.
Informations essentielles
Origine : Cybozu (Japon) → CNCF · Licence : Apache 2.0 · Architectures : x86_64, ARM64
Liens : Site officiel · Documentation · GitHub · Releases
Support : Communauté GitHub. Cybozu maintient le projet activement.
Stack par défaut
| Composant | Valeur |
|---|---|
| Type de stockage | Local (LVM Logical Volumes) |
| Réplication | Aucune - données locales uniquement |
| Thin provisioning | Oui (LVM thin pools) |
| Scheduling | Capacity-aware (informe le scheduler K8s de l'espace disponible) |
| Access modes | ReadWriteOnce uniquement |
| Extension de volume | Oui (online resize via LVM) |
| Kubernetes minimum | 1.20+ |
Composants
| Composant | Rôle | Déploiement |
|---|---|---|
| topolvm-controller | Provisionne les LV, gère les PVC | Deployment |
| topolvm-node | Gère les LV sur chaque nœud, expose la capacité | DaemonSet |
| topolvm-scheduler | Extender du scheduler K8s - utilise la capacité LVM | Deployment ou config kube-scheduler |
Prérequis
| Ressource | Valeur |
|---|---|
| Kubernetes | 1.20+ |
| OS | Linux avec LVM2 installé |
| LVM | Volume Group(s) créé(s) sur chaque nœud de stockage |
| Droits | cluster-admin |
Préparer LVM sur chaque nœud de stockage
# Installer LVM2
sudo apt-get install -y lvm2 # Ubuntu/Debian
sudo dnf install -y lvm2 # Rocky/AlmaLinux
# Créer un Physical Volume sur le disque dédié
sudo pvcreate /dev/sdb
# Créer un Volume Group (nommé par convention "myvg" ou selon le paramètre storageClass)
sudo vgcreate myvg /dev/sdb
# Vérifier
sudo vgs
sudo pvs
TopoLVM créera des Logical Volumes dans ce VG à la demande. Ne pas créer de LV manuellement dans le VG utilisé par TopoLVM.
Installation
Via Helm (recommandé)
helm repo add topolvm https://topolvm.github.io/topolvm
helm repo update
# Installer TopoLVM
helm install topolvm topolvm/topolvm \
--namespace topolvm-system \
--create-namespace \
--set scheduler.enabled=true
kubectl get pods -n topolvm-system
Options clés
# topolvm-values.yaml
controller:
storageCapacityTracking:
enabled: true # Capacity-aware scheduling
node:
volumeGroupName: myvg # Nom du VG LVM à utiliser sur les nœuds
scheduler:
enabled: true # Activer l'extender du scheduler
helm install topolvm topolvm/topolvm \
-n topolvm-system --create-namespace \
-f topolvm-values.yaml
Configuration
Annoter les nœuds avec le VG LVM
TopoLVM doit savoir quel VG utiliser sur chaque nœud :
# Annoter un nœud avec le nom du VG
kubectl annotate node node1 topolvm.io/capacity-key-prefix=topolvm.io
kubectl label node node1 topolvm.io/node=node1
Ou via la configuration du DaemonSet (voir values.yaml → node.devices).
StorageClass
# thin provisioning (recommandé - meilleur usage de l'espace)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: topolvm-provisioner-thin
provisioner: topolvm.io
parameters:
"topolvm.io/device-class": thin # Utiliser un thin pool LVM
volumeBindingMode: WaitForFirstConsumer # OBLIGATOIRE pour local storage
allowVolumeExpansion: true
reclaimPolicy: Delete
---
# thick provisioning (alloué immédiatement)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: topolvm-provisioner-thick
provisioner: topolvm.io
parameters:
"topolvm.io/device-class": "" # Thick LV par défaut
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
reclaimPolicy: Delete
WaitForFirstConsumerest obligatoire pour le stockage local : cela garantit que le PV est créé sur le même nœud que le pod.
Vérification de l'installation
# 1. Pods TopoLVM
kubectl get pods -n topolvm-system
# topolvm-controller, topolvm-node (DaemonSet, 1 par nœud), topolvm-scheduler
# 2. Vérifier que la capacité LVM est bien détectée et remontée au scheduler
kubectl get nodes -o custom-columns=\
"NODE:.metadata.name,CAPACITY:.status.allocatable.topolvm\.io/capacity"
# Chaque nœud doit afficher sa capacité LVM disponible (en octets)
# "0" ou "<none>" = le VG n'est pas détecté (voir pièges ci-dessous)
# 3. Vérifier les StorageClasses
kubectl get sc | grep topolvm
# 4. Vérifier les logs du node daemon sur un nœud spécifique
kubectl logs -n topolvm-system \
$(kubectl get pod -n topolvm-system -l app.kubernetes.io/component=node \
-o jsonpath='{.items[0].metadata.name}') --tail=30
Pièges courants à l'installation
| Symptôme | Cause | Correction |
|---|---|---|
| Capacité = 0 sur tous les nœuds | Le nom du VG dans values.yaml ne correspond pas au VG créé | Vérifier sudo vgs sur le nœud et corriger node.volumeGroupName |
PVC reste Pending | WaitForFirstConsumer attend un pod | Normal - créer le pod qui utilise le PVC pour déclencher le binding |
PVC reste Pending après création du pod | Nœud schedulé sur un nœud sans espace LVM | Vérifier la capacité par nœud, ajouter de l'espace au VG |
| LVM non installé | vgs introuvable sur les nœuds | apt-get install -y lvm2 + pvcreate + vgcreate sur chaque nœud |
Premier test de bout en bout
# test-topolvm.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-topolvm-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: topolvm-provisioner-thin
resources:
requests:
storage: 1Gi
---
apiVersion: v1
kind: Pod
metadata:
name: test-topolvm
namespace: default
spec:
containers:
- name: writer
image: busybox
command: ["/bin/sh", "-c"]
args:
- |
echo "TopoLVM OK - nœud: $NODE_NAME" > /data/test.txt
cat /data/test.txt
df -h /data
sleep 3600
env:
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: test-topolvm-pvc
kubectl apply -f test-topolvm.yaml
# Le PVC se bind uniquement quand le pod est schedulé (WaitForFirstConsumer)
kubectl get pvc test-topolvm-pvc -w
# Pending → Bound (en quelques secondes après scheduling du pod)
kubectl logs test-topolvm
# Doit afficher le message + le nœud choisi + df -h avec ~1G disponible
# Vérifier le LV créé sur le nœud (se connecter sur le nœud)
kubectl get pv $(kubectl get pvc test-topolvm-pvc -o jsonpath='{.spec.volumeName}') \
-o jsonpath='{.spec.nodeAffinity.required.nodeSelectorTerms[*]}'
# Affiche le nœud sur lequel le LV a été créé
# Sur ce nœud : sudo lvs | grep <pv-name>
# Nettoyage
kubectl delete -f test-topolvm.yaml
Utilisation
# PVC TopoLVM
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: local-data
namespace: production
spec:
accessModes:
- ReadWriteOnce
storageClassName: topolvm-provisioner-thin
resources:
requests:
storage: 20Gi
Le scheduler Kubernetes, aidé par l'extender TopoLVM, choisit automatiquement un nœud ayant 20+ Gi disponibles dans son VG LVM.
Vérifier l'espace disponible par nœud
# Capacité LVM reportée à Kubernetes
kubectl get nodes -o custom-columns=\
"NAME:.metadata.name,\
CAPACITY:.status.allocatable.topolvm\.io/capacity"
# Ou via les annotations
kubectl describe node node1 | grep topolvm
Extension de volume
# Éditer le PVC pour augmenter la taille
kubectl patch pvc local-data -n production \
-p '{"spec":{"resources":{"requests":{"storage":"40Gi"}}}}'
# Le LV est étendu en ligne par TopoLVM (le pod n'a pas besoin d'être arrêté)
kubectl get pvc local-data -n production
Thin provisioning (LVM thin pools)
Pour utiliser le thin provisioning, créer un thin pool dans le VG avant l'installation :
# Créer un thin pool "thin" dans le VG "myvg" (utilise 100% de l'espace VG)
sudo lvcreate -l 100%FREE --thinpool thin myvg
# Vérifier
sudo lvs
Puis configurer la StorageClass avec "topolvm.io/device-class": "thin".
Mise à jour
helm repo update
helm upgrade topolvm topolvm/topolvm \
-n topolvm-system \
--reuse-values
kubectl rollout status deploy/topolvm-controller -n topolvm-system
kubectl rollout status ds/topolvm-node -n topolvm-system
Troubleshooting
# État des pods TopoLVM
kubectl get pods -n topolvm-system
# Logs du controller
kubectl logs -n topolvm-system -l app.kubernetes.io/component=controller --tail=100
# Logs du node daemon
kubectl logs -n topolvm-system -l app.kubernetes.io/component=node --tail=100
# Vérifier les LV créés sur un nœud
sudo lvs | grep -v LVM2
PVC bloqué en Pending
kubectl describe pvc <nom> -n <namespace>
# Events : souvent "no nodes are available that match all of the following predicates: Insufficient topolvm.io/capacity"
# Vérifier l'espace LVM disponible par nœud
kubectl get nodes -o yaml | grep topolvm
# Sur le nœud lui-même
sudo vgs # Espace total / libre dans le VG
sudo lvs # LVs existants
Extension de volume échouée
# Vérifier que le thin pool n'est pas plein
sudo lvs -a | grep thin # data% et meta% < 100%
# Si plein, étendre le thin pool
sudo lvextend -l +100%FREE myvg/thin
Commandes utiles
# K8s
kubectl get pvc -n <namespace> | grep topolvm
kubectl get pv | grep topolvm
# Sur les nœuds de stockage
sudo vgs # Volume Groups et espace
sudo pvs # Physical Volumes
sudo lvs # Logical Volumes (un par PVC)
sudo lvs -a # Inclure thin pools et metadata LVs
sudo vgdisplay myvg # Détail d'un VG
Ressources
- Documentation TopoLVM : https://github.com/topolvm/topolvm/tree/main/docs
- Getting started : https://github.com/topolvm/topolvm/blob/main/docs/getting-started.md
- Scheduler extender : https://github.com/topolvm/topolvm/blob/main/docs/scheduler.md
- GitHub : https://github.com/topolvm/topolvm
- Releases : https://github.com/topolvm/topolvm/releases