Aller au contenu
medium

Longhorn : stockage Kubernetes répliqué et simplifié

39 min de lecture

logo longhorn

Longhorn transforme les disques locaux de vos nœuds Kubernetes en stockage persistant répliqué via iSCSI, avec une interface web intégrée pour tout superviser. Projet CNCF Incubating développé par Rancher Labs (SUSE), il se distingue par sa simplicité de mise en œuvre : aucune configuration noyau spéciale, aucun HugePages, aucun cœur CPU dédié. Ce guide vous accompagne du déploiement sur un cluster 3 nœuds à la création de volumes répliqués, snapshots, expansion et backups, avec toutes les commandes testées sur Ubuntu 24.04.

Le parcours part de l'architecture pour aboutir à un cluster utilisable, chaque commande ayant été rejouée sur trois VM KVM sous Ubuntu 24.04 avec k3s.

  • Architecture microservices : Longhorn Manager, Engine, Instance Manager
  • Réplication iSCSI : chaque volume dispose de son propre contrôleur
  • Lab complet : déployer Longhorn v1.11 sur 3 VMs KVM avec k3s
  • Volumes répliqués : StorageClass, PVC, déploiement PostgreSQL
  • Snapshots CSI : sauvegarder et restaurer un volume
  • Interface web : superviser volumes, nœuds et réplicas
  • Expansion en ligne : agrandir un volume sans interruption
  • Dépannage et bonnes pratiques : diagnostic, sécurité, dimensionnement

Longhorn est une solution de stockage bloc distribué pour Kubernetes créée en 2017 par Rancher Labs (aujourd'hui SUSE). Elle suit une architecture microservices : chaque volume possède son propre contrôleur (Longhorn Engine), tourné dans un pod dédié. Les données sont répliquées via iSCSI sur plusieurs nœuds pour assurer la haute disponibilité.

Ces caractéristiques dessinent un compromis assumé : Longhorn privilégie la simplicité d'exploitation et les prérequis minimaux plutôt que la performance brute, ce qui explique le choix d'iSCSI plutôt que de NVMe-oF.

CaractéristiqueDescription
MicroservicesUn contrôleur (Engine) par volume, isolation maximale
Réplication iSCSIDonnées répliquées sur 2 ou 3 nœuds via iSCSI
Interface web intégréeDashboard pour superviser volumes, nœuds, snapshots
Snapshots et backupsSnapshots locaux + backups vers NFS ou S3
Expansion en ligneAgrandir un volume sans arrêter le pod
Kubernetes-natifInstallation Helm, StorageClass par défaut, CSI complet
CNCF IncubatingProjet hébergé par la Cloud Native Computing Foundation
Prérequis minimauxJuste open-iscsi, pas de HugePages, pas de CPU dédiés

Les lignes prérequis noyau et CPU par nœud sont celles qui décident en pratique : elles déterminent si la solution tient sur les machines dont vous disposez déjà. Les colonnes ne sont pas classées de la moins bonne à la meilleure, chaque moteur visant un profil de cluster différent.

CritèreLonghornOpenEBS (Mayastor)Rook-CephNFS classique
ProtocoleiSCSINVMe-oFRADOSNFS
PerformanceModéréeTrès élevéeÉlevéeFaible
ComplexitéFaibleModéréeÉlevéeTrès faible
Prérequis noyauopen-iscsiHugePages + nvme-tcpAucunAucun
CPU par nœudFaible (~0.25 cœur)2 cœurs dédiésVariableNégligeable
RAM par nœud~512 Mo2+ Go (HugePages)~1 GoNégligeable
Interface webOuiNonDashboard CephNon
Backups S3NatifNonNatif (RGW)Non
Cas d'usagePetits/moyens clustersBases de données haute perfCloud privé completPartages simples

Comprendre le découpage interne évite de se tromper de piste lors d'un incident : un volume dégradé, un pod bloqué au montage et une réplica non planifiée relèvent de trois composants distincts. Cette partie détaille le modèle microservices, le rôle de chaque brique, le chemin d'une écriture, puis la StorageClass créée à l'installation.

Contrairement à Ceph ou GlusterFS qui utilisent un processus monolithique, Longhorn crée un contrôleur dédié pour chaque volume. Ce modèle offre une isolation complète : un problème sur un volume n'affecte pas les autres.

Six composants se répartissent le travail, tous déployés dans le namespace longhorn-system. La distinction utile au dépannage sépare le plan de contrôle, Manager et CSI Driver, du plan de données, Engine et Replica, portés par l'Instance Manager.

  • Longhorn Manager : un DaemonSet qui tourne sur chaque nœud. Il gère le cycle de vie des volumes (création, suppression, expansion), orchestre la réplication et expose l'API Longhorn. C'est le cerveau du système.

  • Longhorn Engine : le contrôleur de données, un par volume. Il reçoit les I/O de l'application via iSCSI et les réplique sur les réplicas distants. Chaque Engine est un processus léger géré par l'Instance Manager.

  • Instance Manager : un pod par nœud qui gère les processus Engine et Replica locaux. Il démarre, arrête et surveille les contrôleurs de chaque volume hébergé sur ce nœud.

  • Share Manager : active le support ReadWriteMany (RWX). Pour les volumes partagés entre plusieurs pods, Longhorn crée un serveur NFS temporaire qui expose le volume bloc en partage fichier.

  • CSI Driver : les composants CSI (Container Storage Interface) font le lien entre Kubernetes (PVC, StorageClass, VolumeSnapshot) et Longhorn. Inclut le provisioner, attacher, resizer et snapshotter.

  • Longhorn UI : interface web React pour superviser les volumes, les nœuds, les réplicas, les snapshots et les backups. Affiche la santé du cluster en temps réel.

Le point déterminant est la dernière étape : l'écriture n'est acquittée qu'une fois toutes les réplicas synchronisées. C'est ce qui garantit la cohérence après la perte d'un nœud, et c'est aussi ce qui explique que la latence d'écriture dépende du réseau entre nœuds, pas seulement du disque local.

  1. L'application écrit des données dans le volume monté (via le PVC).

  2. Le CSI Driver transmet l'I/O au Longhorn Engine du volume via iSCSI.

  3. Le Longhorn Engine écrit simultanément sur toutes les réplicas (par défaut 3, une par nœud).

  4. Chaque Replica persiste les données sur le disque local du nœud (dans /var/lib/longhorn/).

  5. L'écriture est confirmée à l'application uniquement quand toutes les réplicas ont acquitté.

À l'installation, Longhorn crée automatiquement une StorageClass longhorn configurée avec 3 réplicas et le filesystem ext4 :

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "30"
fsType: "ext4"

Les paramètres clés :

ParamètreValeur par défautDescription
numberOfReplicas3Nombre de copies des données
staleReplicaTimeout30Minutes avant de considérer une réplica obsolète
fsTypeext4Système de fichiers du volume
allowVolumeExpansiontrueAutorise l'expansion en ligne
dataLocalitydisabledbest-effort place une réplica sur le nœud du pod
fromBackupvideURL d'un backup pour restaurer un volume

Le lab part de trois VM vierges et va jusqu'au cluster k3s avec Longhorn opérationnel et sa StorageClass par défaut. Deux points conditionnent la réussite : iscsid doit être actif sur chaque nœud, faute de quoi tout montage de volume échoue, et un disque dédié monté sur /var/lib/longhorn isole les I/O du stockage de celles du système.

Trois nœuds sont le minimum réel, pas une recommandation : la valeur par défaut de trois réplicas exige autant de nœuds éligibles, sinon la planification échoue.

  • 3 machines virtuelles Ubuntu 24.04 (KVM, Proxmox ou cloud)
  • 2 vCPU et 4 Go de RAM minimum par VM
  • 1 disque système (30 Go) + 1 disque dédié (20 Go minimum) par VM
  • open-iscsi installé et iscsid actif sur chaque nœud
  • Kubernetes 1.25+ (k3s, kubeadm ou cloud managé)

Chaque VM reçoit deux disques : le disque système et un disque data de 20 Go que Longhorn utilisera exclusivement. Le fichier cloud-init installe open-iscsi et active iscsid dès le premier démarrage, ce qui évite d'y revenir après l'installation de Kubernetes.

Le script suivant crée 3 VMs avec cloud-init, chacune avec 2 disques :

#!/bin/bash
# Créer 3 VMs pour le lab Longhorn
IMAGE="/var/lib/libvirt/images/ubuntu-24.04-cloud.img"
for i in 1 2 3; do
# Disque système (backing file pour économiser de l'espace)
qemu-img create -f qcow2 -b "$IMAGE" -F qcow2 \
"/var/lib/libvirt/images/longhorn-${i}-os.qcow2" 30G
# Disque data dédié pour Longhorn
qemu-img create -f qcow2 \
"/var/lib/libvirt/images/longhorn-${i}-data.qcow2" 20G
virt-install \
--name "longhorn-${i}" \
--vcpus 2 --memory 4096 \
--disk "/var/lib/libvirt/images/longhorn-${i}-os.qcow2" \
--disk "/var/lib/libvirt/images/longhorn-${i}-data.qcow2" \
--cloud-init "user-data=cloud-init.yaml" \
--os-variant ubuntu24.04 \
--network network=default,model=virtio \
--noautoconsole --import --quiet
done

Sur chaque nœud, formatez et montez le disque data :

Fenêtre de terminal
# Formater le disque dédié en ext4
sudo mkfs.ext4 -F /dev/vdb
# Créer le point de montage Longhorn
sudo mkdir -p /var/lib/longhorn
# Monter le disque
sudo mount /dev/vdb /var/lib/longhorn
# Rendre le montage persistant
echo '/dev/vdb /var/lib/longhorn ext4 defaults 0 2' | sudo tee -a /etc/fstab
# Vérification
df -h /var/lib/longhorn
# Filesystem Size Used Avail Use% Mounted on
# /dev/vdb 20G 24K 19G 1% /var/lib/longhorn

Deux composants de k3s sont désactivés volontairement : Traefik, inutile ici, et surtout local-storage, dont la StorageClass entrerait en concurrence avec celle de Longhorn pour le statut de classe par défaut.

  1. Installer k3s sur le premier nœud (serveur) :

    Fenêtre de terminal
    # Sur longhorn-1 : installer k3s sans traefik ni local-storage
    curl -sfL https://get.k3s.io | \
    INSTALL_K3S_EXEC='--disable traefik --disable local-storage' sh -
    # Récupérer le token de jonction
    sudo cat /var/lib/rancher/k3s/server/node-token

    L'option --disable local-storage est importante : elle évite le conflit avec la StorageClass par défaut de Longhorn.

  2. Joindre les agents au cluster :

    Fenêtre de terminal
    # Sur longhorn-2 et longhorn-3
    curl -sfL https://get.k3s.io | \
    K3S_URL='https://192.168.122.89:6443' \
    K3S_TOKEN='K10c1a7b9...' sh -
  3. Vérifier le cluster :

    Fenêtre de terminal
    sudo kubectl get nodes -o wide
    # NAME STATUS ROLES AGE VERSION
    # longhorn-1 Ready control-plane 81s v1.34.4+k3s1
    # longhorn-2 Ready <none> 40s v1.34.4+k3s1
    # longhorn-3 Ready <none> 26s v1.34.4+k3s1

Le chart déploie l'ensemble des composants et crée la StorageClass longhorn en classe par défaut. Le paramètre defaultDataPath doit pointer vers le disque dédié monté précédemment : laissé à sa valeur d'origine, Longhorn écrirait sur le disque système sans le signaler.

  1. Installer Helm (si absent) :

    Fenêtre de terminal
    curl -fsSL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 -o get-helm-3.sh
    bash get-helm-3.sh
  2. Ajouter le dépôt Longhorn :

    Fenêtre de terminal
    sudo helm repo add longhorn https://charts.longhorn.io
    sudo helm repo update
  3. Déployer Longhorn v1.11 :

    Fenêtre de terminal
    sudo KUBECONFIG=/etc/rancher/k3s/k3s.yaml \
    helm install longhorn longhorn/longhorn \
    --namespace longhorn-system \
    --create-namespace \
    --version 1.11.0 \
    --set defaultSettings.defaultDataPath=/var/lib/longhorn \
    --set defaultSettings.defaultReplicaCount=3 \
    --set persistence.defaultClassReplicaCount=3

    Paramètres importants :

    Paramètre HelmValeurDescription
    defaultSettings.defaultDataPath/var/lib/longhornChemin de stockage sur chaque nœud
    defaultSettings.defaultReplicaCount3Nombre de réplicas par volume
    persistence.defaultClassReplicaCount3Réplicas dans la StorageClass par défaut
  4. Vérifier le déploiement (2-3 minutes) :

    Fenêtre de terminal
    sudo kubectl get pods -n longhorn-system
    # NAME READY STATUS AGE
    # csi-attacher-896ffc747-lwmv5 1/1 Running 3m
    # csi-provisioner-688964c44b-m5g82 1/1 Running 3m
    # csi-resizer-6585bb54-vf6t9 1/1 Running 3m
    # csi-snapshotter-65884686fc-2cbrq 1/1 Running 3m
    # engine-image-ei-ff1cedad-2fwgx 1/1 Running 3m
    # engine-image-ei-ff1cedad-mvg9n 1/1 Running 3m
    # engine-image-ei-ff1cedad-tvs6k 1/1 Running 3m
    # instance-manager-... 1/1 Running 3m
    # longhorn-csi-plugin-74st2 3/3 Running 3m
    # longhorn-csi-plugin-cz59x 3/3 Running 3m
    # longhorn-csi-plugin-zh6qc 3/3 Running 3m
    # longhorn-driver-deployer-5fc94646bf-m65tp 1/1 Running 3m
    # longhorn-manager-7rjbw 2/2 Running 3m
    # longhorn-manager-7x9qp 2/2 Running 3m
    # longhorn-manager-s77df 2/2 Running 3m
    # longhorn-ui-7fc9b4667f-9kh9x 1/1 Running 3m

    18 pods au total : 3 managers (DaemonSet), 3 engine images (DaemonSet), 3 instance managers, 3 CSI plugins (DaemonSet), 4 composants CSI, 1 driver deployer, 1 UI.

  5. Vérifier la StorageClass et les nœuds :

    Fenêtre de terminal
    sudo kubectl get sc
    # NAME PROVISIONER RECLAIMPOLICY ALLOWVOLUMEEXPANSION
    # longhorn (default) driver.longhorn.io Delete true
    sudo kubectl get nodes.longhorn.io -n longhorn-system
    # NAME SCHEDULABLE
    # longhorn-1 true
    # longhorn-2 true
    # longhorn-3 true

Cette partie vérifie le fonctionnement de bout en bout : un PVC réclame 2 Go, Longhorn provisionne un volume et place trois réplicas sur trois nœuds, puis PostgreSQL écrit des données réellement persistées. Les commandes de contrôle interrogent les objets volumes.longhorn.io et replicas.longhorn.io, qui montrent l'état réel côté stockage, invisible depuis les objets Kubernetes standards.

Créez un PVC de 2 Go avec la StorageClass longhorn (par défaut, 3 réplicas) :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 2Gi

La variable PGDATA pointe vers un sous-répertoire du montage : PostgreSQL refuse d'initialiser sa base dans un répertoire contenant déjà lost+found, que crée toute formation ext4.

apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16-alpine@sha256:57c72fd2a128e416c7fcc499958864df5301e940bca0a56f58fddf30ffc07777
env:
- name: POSTGRES_PASSWORD
value: longhorn-test
- name: PGDATA
value: /var/lib/postgresql/data/pgdata
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumes:
- name: data
persistentVolumeClaim:
claimName: postgres-data

Le champ robustness est l'indicateur à surveiller : healthy signale que les trois copies sont synchronisées. La liste des réplicas confirme leur répartition sur des nœuds distincts, condition sans laquelle la réplication ne protège de rien.

Fenêtre de terminal
# Le PVC est lié à un volume Longhorn
sudo kubectl get pvc
# NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS
# postgres-data Bound pvc-55aef... 2Gi RWO longhorn
# Le volume est attaché avec 3 réplicas
sudo kubectl get volumes.longhorn.io -n longhorn-system \
-o custom-columns='NAME:.metadata.name,STATE:.status.state,ROBUSTNESS:.status.robustness,REPLICAS:.spec.numberOfReplicas'
# NAME STATE ROBUSTNESS REPLICAS
# pvc-55aef5a4... attached healthy 3
# Les 3 réplicas tournent sur des nœuds différents
sudo kubectl get replicas.longhorn.io -n longhorn-system \
-o custom-columns='NAME:.metadata.name,NODE:.spec.nodeID,STATE:.status.currentState'
# NAME NODE STATE
# pvc-55aef...-r-098e947d longhorn-2 running
# pvc-55aef...-r-3a6dc1b3 longhorn-1 running
# pvc-55aef...-r-4e63429a longhorn-3 running

Ces mille lignes servent de témoin pour la suite : elles seront recherchées à l'identique dans le volume restauré depuis le snapshot.

Fenêtre de terminal
# Écrire 1000 lignes dans PostgreSQL
POD=$(sudo kubectl get pods -l app=postgres -o jsonpath='{.items[0].metadata.name}')
sudo kubectl exec $POD -- psql -U postgres -c \
"CREATE TABLE test_longhorn (id SERIAL PRIMARY KEY, data TEXT, created_at TIMESTAMP DEFAULT NOW());"
sudo kubectl exec $POD -- psql -U postgres -c \
"INSERT INTO test_longhorn (data) SELECT 'Row ' || generate_series(1, 1000);"
# Vérifier les données
sudo kubectl exec $POD -- psql -U postgres -c "SELECT count(*) FROM test_longhorn;"
# count
# -------
# 1000

Les snapshots passent par l'API VolumeSnapshot de Kubernetes, pas par une commande propre à Longhorn. Trois objets sont nécessaires : les CRDs et leur contrôleur, une VolumeSnapshotClass qui désigne le driver, puis le snapshot lui-même. La restauration ne remplace pas le volume d'origine : elle crée un nouveau PVC alimenté par le snapshot.

Les CRDs VolumeSnapshot ne sont pas toujours installés par défaut dans k3s. Installez-les si nécessaire :

Fenêtre de terminal
# CRDs VolumeSnapshot
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v8.2.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v8.2.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v8.2.1/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml
# Snapshot Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v8.2.1/deploy/kubernetes/snapshot-controller/rbac-snapshot-controller.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/v8.2.1/deploy/kubernetes/snapshot-controller/setup-snapshot-controller.yaml

Le paramètre type décide de la nature de l'opération, et c'est le seul réglage réellement structurant de cet objet.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
name: longhorn-snapshot-vsc
driver: driver.longhorn.io
deletionPolicy: Delete
parameters:
type: snap

Le paramètre type: snap crée un snapshot natif Longhorn (rapide, ne consomme que l'espace des blocs modifiés). Utilisez type: bak pour créer un backup exportable vers NFS ou S3.

Le snapshot référence le PVC source et non le volume Longhorn sous-jacent. L'opération n'interrompt pas le pod, mais elle fige l'état des blocs au moment de la demande, y compris d'éventuelles écritures non encore transmises par l'application.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: postgres-snap-1
spec:
volumeSnapshotClassName: longhorn-snapshot-vsc
source:
persistentVolumeClaimName: postgres-data

Vérification :

Fenêtre de terminal
sudo kubectl get volumesnapshot
# NAME READYTOUSE SOURCEPVC RESTORESIZE SNAPSHOTCLASS
# postgres-snap-1 true postgres-data 2Gi longhorn-snapshot-vsc

Le snapshot est prêt quand READYTOUSE passe à true (quelques secondes).

Créez un nouveau PVC qui référence le snapshot comme source de données :

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-restore
spec:
accessModes:
- ReadWriteOnce
storageClassName: longhorn
resources:
requests:
storage: 2Gi
dataSource:
name: postgres-snap-1
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io

Vérifier les données restaurées :

Fenêtre de terminal
# Démarrer un pod avec le volume restauré
sudo kubectl run postgres-verify --image=postgres:16-alpine \
--env="POSTGRES_PASSWORD=longhorn-test" \
--env="PGDATA=/var/lib/postgresql/data/pgdata" \
--overrides='{
"spec": {
"containers": [{
"name": "postgres-verify",
"image": "postgres:16-alpine",
"env": [
{"name": "POSTGRES_PASSWORD", "value": "longhorn-test"},
{"name": "PGDATA", "value": "/var/lib/postgresql/data/pgdata"}
],
"volumeMounts": [{"name": "data", "mountPath": "/var/lib/postgresql/data"}]
}],
"volumes": [{
"name": "data",
"persistentVolumeClaim": {"claimName": "postgres-restore"}
}]
}
}'
# Attendre le démarrage puis vérifier
sudo kubectl exec postgres-verify -- psql -U postgres -c "SELECT count(*) FROM test_longhorn;"
# count
# -------
# 1000

Les 1000 lignes sont intactes : la restauration fonctionne.

Longhorn inclut un dashboard web complet qui permet de superviser et gérer l'ensemble du stockage sans ligne de commande.

Par défaut, le service longhorn-frontend est de type ClusterIP. Pour y accéder, exposez-le via NodePort :

Fenêtre de terminal
sudo kubectl -n longhorn-system patch svc longhorn-frontend \
--type merge -p '{"spec":{"type":"NodePort","ports":[{"port":80,"targetPort":8000,"nodePort":30080}]}}'
# L'UI est accessible sur http://<IP-noeud>:30080
curl -s -o /dev/null -w "%{http_code}" http://192.168.122.89:30080/
# 200

Deux opérations n'ont pas d'équivalent pratique en ligne de commande et justifient à elles seules l'usage de l'interface : la configuration de la cible de backup et la planification des recurring jobs.

  • Dashboard : vue d'ensemble de la santé du cluster, espace utilisé, volumes dégradés
  • Volumes : état, réplicas, snapshots, taille, nœud d'attachement
  • Nœuds : disques, espace disponible, statut de planification
  • Snapshots : créer, supprimer, restaurer depuis l'UI
  • Backups : configurer la cible (NFS/S3), planifier des backups récurrents
  • Paramètres : modifier les réglages globaux (nombre de réplicas, localité, rétention)

Longhorn prend en charge l'expansion de volume sans interruption du pod utilisateur. La StorageClass par défaut a allowVolumeExpansion: true.

L'expansion ne se demande pas à Longhorn mais au PVC : c'est Kubernetes qui propage la nouvelle taille au driver CSI. La réduction n'est jamais possible, dans un sens comme dans l'autre.

Fenêtre de terminal
# Étendre le PVC
sudo kubectl patch pvc postgres-data \
--type merge -p '{"spec":{"resources":{"requests":{"storage":"4Gi"}}}}'
# persistentvolumeclaim/postgres-data patched
# Vérifier l'expansion (15-30 secondes)
sudo kubectl get pvc postgres-data
# NAME STATUS VOLUME CAPACITY STORAGECLASS
# postgres-data Bound pvc-55aef... 4Gi longhorn

L'expansion se fait en trois étapes automatiques :

  1. Longhorn étend le volume bloc sous-jacent et chaque réplica
  2. Le CSI resizer étend le device iSCSI attaché au pod
  3. Le filesystem ext4 est agrandi en ligne (sans démontage)

Longhorn peut sauvegarder les volumes vers un stockage externe (NFS ou S3-compatible) pour le disaster recovery.

Via l'UI ou le CLI, définissez la cible dans les paramètres Longhorn :

/backup/longhorn
# Cible NFS
sudo kubectl -n longhorn-system edit settings.longhorn.io backup-target
# Cible S3 (MinIO, AWS S3)
# Valeur : s3://longhorn-backups@us-east-1/
# + créer un Secret avec les credentials S3

Longhorn supporte les recurring jobs pour automatiser les snapshots et backups. Configurez-les via l'UI ou un CRD RecurringJob :

apiVersion: longhorn.io/v1beta2
kind: RecurringJob
metadata:
name: backup-daily
namespace: longhorn-system
spec:
cron: "0 2 * * *"
task: backup
retain: 7
concurrency: 1
groups:
- default

Ce job effectue un backup quotidien à 2h du matin et conserve les 7 derniers.

Longhorn n'a pas de binaire client : toute l'administration passe par kubectl sur ses CRDs (volumes, replicas, nodes, settings) et par Helm pour le cycle de vie du chart. Les objets Kubernetes standards, PVC et PV, ne montrent pas l'état de la réplication.

Les objets volumes.longhorn.io exposent l'état réel du stockage, notamment la robustesse et le nombre de réplicas effectivement en service.

Fenêtre de terminal
# Lister les volumes Longhorn
sudo kubectl get volumes.longhorn.io -n longhorn-system
# Détails d'un volume
sudo kubectl describe volumes.longhorn.io <nom-volume> -n longhorn-system
# Lister les réplicas et leur nœud
sudo kubectl get replicas.longhorn.io -n longhorn-system \
-o custom-columns='NAME:.metadata.name,NODE:.spec.nodeID,STATE:.status.currentState'
# Lister les engine images
sudo kubectl get engineimages.longhorn.io -n longhorn-system

Passer allowScheduling à false empêche la création de nouvelles réplicas sur le nœud sans supprimer celles qui s'y trouvent déjà : c'est l'étape préalable à toute maintenance.

Fenêtre de terminal
# Lister les nœuds Longhorn et leurs disques
sudo kubectl get nodes.longhorn.io -n longhorn-system
# Désactiver la planification sur un nœud (maintenance)
sudo kubectl patch nodes.longhorn.io longhorn-3 -n longhorn-system \
--type merge -p '{"spec":{"allowScheduling":false}}'
# Réactiver
sudo kubectl patch nodes.longhorn.io longhorn-3 -n longhorn-system \
--type merge -p '{"spec":{"allowScheduling":true}}'

La désinstallation supprime les CRDs et donc les volumes qu'ils décrivent ; sauvegardez avant, aucune confirmation n'est demandée.

Fenêtre de terminal
# Vérifier la version installée
sudo KUBECONFIG=/etc/rancher/k3s/k3s.yaml helm list -n longhorn-system
# NAME NAMESPACE REVISION STATUS CHART APP VERSION
# longhorn longhorn-system 1 deployed longhorn-1.11.0 v1.11.0
# Mettre à jour Longhorn
sudo KUBECONFIG=/etc/rancher/k3s/k3s.yaml helm upgrade longhorn longhorn/longhorn \
--namespace longhorn-system --version 1.11.1
# Désinstaller (attention : supprime tous les volumes !)
sudo KUBECONFIG=/etc/rancher/k3s/k3s.yaml helm uninstall longhorn -n longhorn-system

Trois angles se cumulent. L'interface web est ouverte par défaut et donne accès à la suppression de volumes, elle doit donc être placée derrière une authentification. Le chiffrement au repos se déclare par StorageClass, pas globalement. Enfin le RBAC limite qui peut manipuler les CRDs, un droit équivalent à un accès complet aux données du cluster.

L'interface web Longhorn n'a pas d'authentification native. Protégez-la avec un Ingress et Basic Auth :

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: longhorn-ingress
namespace: longhorn-system
annotations:
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: longhorn-basic-auth
nginx.ingress.kubernetes.io/auth-realm: 'Longhorn UI'
spec:
ingressClassName: nginx
rules:
- host: longhorn.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: longhorn-frontend
port:
number: 80

Longhorn supporte le chiffrement au repos via la fonctionnalité CSI encryption. Configurez une StorageClass avec chiffrement :

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn-encrypted
provisioner: driver.longhorn.io
allowVolumeExpansion: true
parameters:
numberOfReplicas: "3"
encrypted: "true"
csi.storage.k8s.io/provisioner-secret-name: longhorn-crypto
csi.storage.k8s.io/provisioner-secret-namespace: longhorn-system
csi.storage.k8s.io/node-publish-secret-name: longhorn-crypto
csi.storage.k8s.io/node-publish-secret-namespace: longhorn-system

Le point le plus souvent négligé est le NodePort ouvert pendant le lab et laissé actif ensuite : il expose l'interface sans authentification sur chaque nœud du cluster.

  • Isoler le namespace longhorn-system avec des NetworkPolicies
  • Chiffrer les backups S3 avec SSE (Server-Side Encryption)
  • RBAC : limiter l'accès aux CRDs Longhorn (volumes, nodes, settings) aux administrateurs uniquement
  • Pas de NodePort en production : utilisez un Ingress sécurisé pour l'UI

La majorité des incidents se ramène à trois familles : iSCSI indisponible sur un nœud, ce qui bloque le montage sans message explicite côté pod ; planification impossible faute de nœuds ou d'espace ; et volumes dégradés après la perte d'un nœud. Le tableau associe le symptôme observé à la vérification qui tranche.

La distinction entre degraded et faulted commande la réponse : le premier état se résorbe seul par re-réplication, le second signifie que plus aucune copie n'est exploitable et impose une restauration.

SymptômeCause probableSolution
Pod bloqué en ContainerCreatingiscsid non actif sur le nœudsystemctl enable --now iscsid
Volume en degradedUn nœud est hors serviceLonghorn re-réplique automatiquement. Vérifiez kubectl get nodes
Volume en faultedToutes les réplicas sont HSVérifiez les disques, espace disponible. Restaurez depuis un backup
Replica scheduling failedPas assez de nœuds ou d'espaceAjoutez un nœud ou libérez de l'espace disque
UI inaccessibleService en ClusterIPChangez en NodePort ou créez un Ingress
Expansion bloquéePod utilisant le PVC en PendingLe pod doit être Running pour l'expansion du filesystem
Volume attachment deadline exceededProblème réseau iSCSIVérifiez la connectivité entre nœuds, iscsiadm -m session
Instance Manager en CrashLoopRessources insuffisantesVérifiez CPU/RAM disponibles, augmentez les limites

iscsiadm -m session se lance sur le nœud, pas dans un pod : les sessions iSCSI appartiennent à l'hôte. Un montage bloqué alors qu'aucune session n'apparaît confirme un problème réseau ou un iscsid arrêté.

Fenêtre de terminal
# Vérifier iscsid sur un nœud
ssh ubuntu@<IP-noeud> "systemctl status iscsid"
# Vérifier les sessions iSCSI
ssh ubuntu@<IP-noeud> "sudo iscsiadm -m session"
# Logs du Longhorn Manager
sudo kubectl logs -n longhorn-system -l app=longhorn-manager --tail=50
# Logs d'un volume spécifique
sudo kubectl describe volumes.longhorn.io <nom-volume> -n longhorn-system
# Vérifier l'espace disque sur chaque nœud
for NODE in longhorn-1 longhorn-2 longhorn-3; do
echo "=== $NODE ==="
ssh ubuntu@<IP-noeud> "df -h /var/lib/longhorn"
done
# Vérifier la santé des réplicas
sudo kubectl get replicas.longhorn.io -n longhorn-system \
-o custom-columns='VOLUME:.spec.volumeName,NODE:.spec.nodeID,STATE:.status.currentState'

Ces règles découlent toutes du même mécanisme : chaque réplica est une copie complète, stockée sur le disque local d'un nœud. La capacité, la topologie et les performances se déduisent donc du nombre de réplicas retenu, et non de la taille des volumes demandés par les applications.

La marge de 25 % n'est pas de la prudence : les snapshots et la re-réplication après incident consomment de l'espace sur le même disque, au moment précis où il en manque.

  • Disque dédié par nœud pour Longhorn (pas sur le disque système)
  • Prévoyez 3× la capacité utile : avec 3 réplicas, un volume de 10 Go consomme 30 Go au total
  • Réservez 25 % d'espace libre sur chaque disque pour les snapshots et la re-réplication
  • Minimum 3 nœuds pour permettre 3 réplicas distinctes

Le nombre de réplicas se fixe par StorageClass, ce qui permet d'en déclarer plusieurs et de choisir au niveau du PVC selon la criticité de la donnée.

  • numberOfReplicas: 3 pour les données critiques (PostgreSQL, MySQL)
  • numberOfReplicas: 2 pour les données importantes mais régénérables
  • numberOfReplicas: 1 uniquement pour les caches et données temporaires
  • dataLocality: best-effort pour placer une réplica sur le nœud du pod (réduit la latence réseau)

Chaque écriture traverse le réseau vers les autres réplicas avant d'être acquittée : la bande passante inter-nœuds pèse ici autant que le débit des disques.

  • Disques SSD pour de meilleures performances I/O
  • Réseau 10 GbE entre les nœuds pour la réplication
  • dataLocality: best-effort réduit les lectures réseau en plaçant un réplica local
  • Recurring jobs en heures creuses pour ne pas impacter les I/O des applications

Une mise à jour de Longhorn touche le plan de données des volumes attachés ; la sauvegarde préalable et la lecture des notes de migration ne sont pas facultatives entre versions mineures.

  • Backups récurrents vers NFS ou S3 avant toute mise à jour
  • Désactivez la planification sur un nœud avant maintenance : kubectl patch nodes.longhorn.io <nœud> -n longhorn-system --type merge -p '{"spec":{"allowScheduling":false}}'
  • Mettez à jour Longhorn via helm upgrade en suivant le guide de migration officiel entre versions majeures
  • Surveillez les alertes de l'UI : volumes dégradés, espace disque faible

Ces points résument le positionnement de Longhorn et les réglages qui conditionnent un déploiement sain : prérequis, réplication, snapshots et sauvegardes externes.

  • Longhorn = stockage répliqué Kubernetes le plus simple à déployer : juste open-iscsi et un disque, pas de HugePages ni de CPU dédiés.
  • Un Engine par volume : architecture microservices avec isolation complète entre les volumes.
  • 3 réplicas par défaut via iSCSI sur des nœuds différents, robustesse healthy quand toutes les copies sont synchronisées.
  • Interface web intégrée pour superviser volumes, nœuds, snapshots et backups sans CLI.
  • Snapshots CSI : sauvegarde en quelques secondes, restauration vers un nouveau PVC.
  • Expansion en ligne : agrandir un volume pendant que le pod tourne (PVC patch + resize automatique ext4).
  • Backups S3/NFS avec des recurring jobs pour le disaster recovery.
  • V2 Data Engine (SPDK) en Technical Preview dans la v1.11 : haute performance en vue pour les prochaines versions stables.

Longhorn couvre le stockage bloc répliqué pour un cluster de taille modeste. OpenEBS Mayastor vise les charges exigeantes en latence via NVMe-oF, Ceph apporte le bloc, l'objet et le fichier dans un même cluster, et MinIO répond au seul besoin de stockage objet compatible S3.

La documentation officielle est versionnée : vérifiez que le sélecteur affiche bien la version installée, les paramètres Helm et les noms de réglages ayant changé entre branches. Les notes de release listent les étapes de migration obligatoires avant tout helm upgrade.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracking. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn