--- title: "Cómo instalar Longhorn en Kubernetes con backups a S3" description: "Instala Longhorn con Helm en un clúster Kubernetes de tres nodos, crea volúmenes replicados y programa snapshots y backups a S3 para proteger tus datos." category: "Ecosistema Kubernetes" language: es source: https://cubepath.com/es/docs/ecosistema-kubernetes/longhorn-almacenamiento-distribuido-kubernetes updated: 2026-09-25 --- # Cómo instalar Longhorn en Kubernetes con backups a S3 Longhorn es un sistema de almacenamiento de bloques distribuido para Kubernetes, mantenido por la CNCF. Convierte los discos locales de los nodos en volúmenes persistentes con réplicas en varios nodos, snapshots y backups a un almacenamiento S3, todo gestionado con recursos de Kubernetes y una interfaz web. En este tutorial prepararás los nodos Ubuntu 24.04, instalarás Longhorn con Helm, crearás un volumen replicado de prueba y configurarás backups diarios a un bucket S3. ## Requisitos previos Para seguir esta guía necesitas: - Un clúster Kubernetes 1.25 o superior con al menos tres nodos worker con Ubuntu 24.04 LTS (por ejemplo, tres VPS de CubePath con kubeadm, k3s o RKE2). - Al menos 2 vCPU y 4 GB de RAM por nodo, y espacio libre en `/var/lib/longhorn` (el directorio de datos por defecto). Un disco o partición dedicada en formato ext4 o XFS es lo recomendable en producción. - `kubectl` configurado con permisos de administrador del clúster y Helm 3 instalado en tu equipo. - Acceso SSH con un usuario con `sudo` en cada nodo. - Para el paso de backups: un bucket S3 (AWS o compatible, como MinIO o Wasabi) y un par de claves de acceso con permisos de lectura y escritura sobre él. ## Paso 1: Preparar los nodos Longhorn expone cada volumen al nodo mediante iSCSI, así que todos los nodos que vayan a montar volúmenes necesitan el iniciador `open-iscsi`. Los volúmenes `ReadWriteMany` se sirven por NFSv4, por lo que también hace falta `nfs-common`. Ejecuta en **cada nodo**: ```bash sudo apt update sudo apt install -y open-iscsi nfs-common ``` Activa el demonio `iscsid` y carga el módulo del kernel `iscsi_tcp`, dejándolo configurado para que se cargue en cada arranque: ```bash sudo systemctl enable --now iscsid sudo modprobe iscsi_tcp echo iscsi_tcp | sudo tee /etc/modules-load.d/iscsi_tcp.conf ``` Comprueba que el servicio está activo y el módulo cargado: ```bash systemctl is-active iscsid lsmod | grep iscsi_tcp ``` ```output active iscsi_tcp 24576 0 ``` Ubuntu trae `multipathd` activo, y este servicio puede apropiarse de los dispositivos que crea Longhorn, lo que provoca errores de montaje del tipo `already mounted or mount point busy`. Si no usas multipath para otros discos, excluye los dispositivos `sd*` editando su configuración: ```bash sudo nano /etc/multipath.conf ``` Añade este bloque al final del archivo: ```text blacklist { devnode "^sd[a-z0-9]+" } ``` Aplica el cambio: ```bash sudo systemctl restart multipathd ``` > Nota: si tus discos de datos también son `sd*` y los gestionas con multipath, ajusta la expresión para excluir solo los dispositivos que no sean tuyos. ## Paso 2: Instalar Longhorn con Helm Añade el repositorio oficial del chart: ```bash helm repo add longhorn https://charts.longhorn.io helm repo update ``` Crea un archivo de valores con los ajustes que querrás revisar en producción: ```bash nano longhorn-values.yaml ``` ```yaml persistence: # Crea la StorageClass "longhorn" y la marca como predeterminada defaultClass: true defaultClassReplicaCount: 3 defaultFsType: ext4 reclaimPolicy: Delete defaultSettings: # Réplicas por defecto para volúmenes creados desde la interfaz defaultReplicaCount: 3 # Directorio de datos en cada nodo defaultDataPath: /var/lib/longhorn/ # Porcentaje mínimo de disco libre para seguir programando réplicas storageMinimalAvailablePercentage: 25 ``` Instala el chart en el namespace `longhorn-system`: ```bash helm install longhorn longhorn/longhorn \ --namespace longhorn-system \ --create-namespace \ --values longhorn-values.yaml ``` La instalación tarda unos minutos, porque Longhorn despliega un manager, un driver CSI y un gestor de instancias en cada nodo. Espera a que el DaemonSet del manager esté listo: ```bash kubectl -n longhorn-system rollout status daemonset/longhorn-manager ``` ```output daemon set "longhorn-manager" successfully rolled out ``` Comprueba que todos los pods están en `Running` y que Longhorn ve los tres nodos como programables: ```bash kubectl -n longhorn-system get pods kubectl -n longhorn-system get nodes.longhorn.io ``` ```output NAME READY ALLOWSCHEDULING SCHEDULABLE AGE worker-1 True true True 3m worker-2 True true True 3m worker-3 True true True 3m ``` Si algún nodo aparece con `READY` a `False`, revisa el paso 1 en ese nodo. > Importante: si tu clúster ya tenía una StorageClass predeterminada (k3s instala `local-path`), ahora tendrás dos. Quita la marca a la antigua con `kubectl patch storageclass local-path -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'`. ## Paso 3: Acceder a la interfaz web La interfaz de Longhorn no tiene autenticación propia, así que no la expongas a Internet sin un Ingress con autenticación. Para administrarla basta con un port-forward desde tu equipo: ```bash kubectl -n longhorn-system port-forward svc/longhorn-frontend 8080:80 ``` Abre `http://localhost:8080` en el navegador. En el panel verás la capacidad total del clúster, los nodos y los volúmenes. Detén el port-forward con `Ctrl+C` cuando termines. ## Paso 4: Crear un volumen replicado y probarlo Crea un namespace de pruebas y un PVC que use la StorageClass `longhorn`: ```bash kubectl create namespace demo-longhorn ``` Crea el manifiesto con el PVC y un pod que escribe en él: ```bash nano pvc-demo.yaml ``` ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: datos-demo namespace: demo-longhorn spec: accessModes: - ReadWriteOnce storageClassName: longhorn resources: requests: storage: 2Gi --- apiVersion: v1 kind: Pod metadata: name: escritor namespace: demo-longhorn spec: containers: - name: app image: busybox:1.36 command: ["sh", "-c", "date >> /datos/log.txt && sleep 3600"] volumeMounts: - name: datos mountPath: /datos volumes: - name: datos persistentVolumeClaim: claimName: datos-demo ``` Aplica el manifiesto y espera a que el pod arranque: ```bash kubectl apply -f pvc-demo.yaml kubectl -n demo-longhorn wait --for=condition=Ready pod/escritor --timeout=180s ``` Comprueba que el PVC está enlazado y que el archivo se ha escrito en el volumen: ```bash kubectl -n demo-longhorn get pvc datos-demo kubectl -n demo-longhorn exec escritor -- cat /datos/log.txt ``` ```output NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE datos-demo Bound pvc-5c1e8d0a-7b7e-4a1f-9f0e-2b8f3c1d9a41 2Gi RWO longhorn 40s ``` Por último, confirma que Longhorn ha creado tres réplicas en nodos distintos y que el volumen está sano: ```bash kubectl -n longhorn-system get volumes.longhorn.io kubectl -n longhorn-system get replicas.longhorn.io -o wide ``` ```output NAME DATA ENGINE STATE ROBUSTNESS SCHEDULED SIZE NODE AGE pvc-5c1e8d0a-7b7e-4a1f-9f0e-2b8f3c1d9a41 v1 attached healthy 2147483648 worker-2 1m ``` `ROBUSTNESS` en `healthy` significa que todas las réplicas están sincronizadas. `degraded` indica que falta alguna y Longhorn la está reconstruyendo. ### StorageClass con otra política de réplicas Si quieres volúmenes más baratos para datos que ya se replican a nivel de aplicación (por ejemplo, un clúster de bases de datos), crea una StorageClass adicional con menos réplicas: ```bash nano storageclass-longhorn-2r.yaml ``` ```yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: longhorn-2r provisioner: driver.longhorn.io allowVolumeExpansion: true reclaimPolicy: Delete volumeBindingMode: Immediate parameters: numberOfReplicas: "2" staleReplicaTimeout: "30" dataLocality: "best-effort" fsType: "ext4" ``` ```bash kubectl apply -f storageclass-longhorn-2r.yaml kubectl get storageclass ``` Con `dataLocality: best-effort`, Longhorn intenta mantener una réplica en el mismo nodo que el pod, lo que reduce la latencia de lectura. ## Paso 5: Configurar backups a S3 Los snapshots de Longhorn viven en los mismos discos que el volumen, así que no protegen ante la pérdida del clúster. Los backups sí: se copian a un almacenamiento externo y se pueden restaurar en otro clúster. Crea un Secret con las credenciales del bucket. Sustituye los valores de ejemplo por los tuyos; `AWS_ENDPOINTS` solo es necesario con proveedores compatibles con S3 distintos de AWS: ```bash kubectl -n longhorn-system create secret generic longhorn-s3-secret \ --from-literal=AWS_ACCESS_KEY_ID='tu_access_key' \ --from-literal=AWS_SECRET_ACCESS_KEY='tu_secret_key' \ --from-literal=AWS_ENDPOINTS='https://s3.tu_proveedor.com' ``` Apunta el destino de backup predeterminado de Longhorn al bucket. El formato de la URL es `s3://@//`: ```bash kubectl -n longhorn-system patch backuptargets.longhorn.io default --type merge \ -p '{"spec":{"backupTargetURL":"s3://tu_bucket@eu-west-1/longhorn/","credentialSecret":"longhorn-s3-secret"}}' ``` Comprueba que Longhorn puede acceder al bucket: ```bash kubectl -n longhorn-system get backuptargets.longhorn.io ``` La columna `AVAILABLE` debe mostrar `true` al cabo de unos segundos. Si muestra `false`, revisa el mensaje con `kubectl -n longhorn-system describe backuptargets.longhorn.io default`; suele ser una región, un endpoint o unas claves incorrectas. ## Paso 6: Programar snapshots y backups automáticos Un `RecurringJob` ejecuta tareas periódicas sobre los volúmenes. Los volúmenes que no tienen ningún job asignado explícitamente pertenecen al grupo `default`, así que asociar los jobs a ese grupo los aplica a todo el clúster. ```bash nano recurring-jobs.yaml ``` ```yaml apiVersion: longhorn.io/v1beta2 kind: RecurringJob metadata: name: snapshot-cada-6h namespace: longhorn-system spec: task: snapshot cron: "0 */6 * * *" groups: - default retain: 4 concurrency: 2 --- apiVersion: longhorn.io/v1beta2 kind: RecurringJob metadata: name: backup-diario namespace: longhorn-system spec: task: backup cron: "0 2 * * *" groups: - default retain: 14 concurrency: 2 ``` Con esta configuración se guardan los últimos 4 snapshots locales (un día) y los últimos 14 backups diarios en S3. ```bash kubectl apply -f recurring-jobs.yaml kubectl -n longhorn-system get recurringjobs.longhorn.io ``` ```output NAME GROUPS TASK CRON RETAIN CONCURRENCY AGE backup-diario ["default"] backup 0 2 * * * 14 2 5s snapshot-cada-6h ["default"] snapshot 0 */6 * * * 4 2 5s ``` Para probar el destino sin esperar a las 2:00, abre la interfaz web, entra en el volumen de prueba y pulsa **Create Backup**. Después lista los backups registrados: ```bash kubectl -n longhorn-system get backups.longhorn.io ``` Un backup en estado `Completed` confirma que toda la cadena funciona. Para restaurarlo, ve a la sección **Backup** de la interfaz, selecciona el backup y usa **Restore**: Longhorn crea un volumen nuevo al que después puedes asociar un PV y un PVC desde la propia interfaz. ## Paso 7: Supervisar Longhorn con Prometheus El manager de Longhorn expone métricas en formato Prometheus en el puerto 9500 del servicio `longhorn-backend`. Compruébalo con un port-forward: ```bash kubectl -n longhorn-system port-forward svc/longhorn-backend 9500:9500 ``` En otra terminal: ```bash curl -s http://localhost:9500/metrics | grep '^longhorn_volume_robustness' ``` ```output longhorn_volume_robustness{node="worker-2",pvc="datos-demo",pvc_namespace="demo-longhorn",volume="pvc-5c1e8d0a-..."} 1 ``` El valor de `longhorn_volume_robustness` es `1` para un volumen sano, `2` degradado y `3` en fallo, por lo que es la métrica natural para una alerta. Si usas Prometheus Operator, crea un `ServiceMonitor` que seleccione el servicio con la etiqueta `app: longhorn-manager` y el puerto `manager`. ## Solución de problemas **El PVC se queda en `Pending`.** Revisa los eventos con `kubectl describe pvc -n `. Lo más habitual es que no haya tres nodos programables con espacio suficiente para colocar las réplicas. Comprueba el espacio en la interfaz o con `kubectl -n longhorn-system get nodes.longhorn.io -o yaml`. **El pod no arranca con `MountVolume.SetUp failed` o `mount point busy`.** Casi siempre es `multipathd` reclamando el dispositivo: aplica la exclusión del paso 1 en el nodo afectado. Si el error menciona iSCSI, comprueba que `iscsid` está activo y que el módulo `iscsi_tcp` está cargado. **Volumen en estado `degraded`.** Longhorn reconstruye la réplica perdida automáticamente cuando hay un nodo disponible. Si no avanza, revisa los logs del manager: ```bash kubectl -n longhorn-system logs -l app=longhorn-manager --tail=100 ``` **Mantenimiento de un nodo.** Antes de reiniciar un nodo, vacíalo con `kubectl drain --ignore-daemonsets --delete-emptydir-data`. Longhorn esperará a que los volúmenes se desconecten de forma limpia. ## Conclusión Tienes Longhorn funcionando como almacenamiento predeterminado del clúster, con volúmenes replicados en tres nodos, snapshots cada seis horas y backups diarios a S3 que sobreviven a la pérdida del clúster. Como siguientes pasos, prueba a restaurar un backup en un clúster de staging para validar tu plan de recuperación, configura alertas sobre `longhorn_volume_robustness` y, si necesitas volúmenes compartidos entre pods, prueba el modo de acceso `ReadWriteMany`.