Almacenamiento OpenEBS para Kubernetes

OpenEBS es una solución de almacenamiento container-attached (CAS) para Kubernetes que ofrece múltiples motores de almacenamiento adaptados a distintas necesidades: desde volúmenes locales de alto rendimiento hasta almacenamiento distribuido replicado. Al ejecutarse completamente en el espacio de usuario como pods de Kubernetes, OpenEBS es fácil de instalar, escalar y operar sin depender de módulos del kernel especiales.

Requisitos Previos

  • Kubernetes 1.23+
  • kubectl configurado con acceso al clúster
  • helm v3 instalado
  • Para iSCSI (Jiva/cStor): open-iscsi en nodos worker
  • Para Mayastor: kernel Linux 5.15+ y soporte para hugepages
# Instalar open-iscsi en todos los nodos worker (Ubuntu/Debian)
apt update && apt install -y open-iscsi
systemctl enable iscsid && systemctl start iscsid

# Para CentOS/Rocky Linux
yum install -y iscsi-initiator-utils
systemctl enable iscsid && systemctl start iscsid

# Verificar el estado del servicio iSCSI
systemctl status iscsid

Instalación de OpenEBS

# Agregar el repositorio Helm de OpenEBS
helm repo add openebs https://openebs.github.io/openebs
helm repo update

# Instalación completa de OpenEBS (todos los motores)
helm install openebs openebs/openebs \
  --namespace openebs \
  --create-namespace \
  --set engines.local.lvm.enabled=true \
  --set engines.replicated.mayastor.enabled=false  # Deshabilitar Mayastor si no hay NVMe

# Instalación mínima (solo LocalPV Hostpath)
helm install openebs openebs/openebs \
  --namespace openebs \
  --create-namespace \
  --set engines.replicated.mayastor.enabled=false \
  --set engines.local.lvm.enabled=false \
  --set engines.local.zfs.enabled=false

# Verificar la instalación
kubectl get pods -n openebs
kubectl get storageclass | grep openebs

LocalPV: Volúmenes Locales de Alto Rendimiento

LocalPV es el motor más simple y de mayor rendimiento de OpenEBS. Los datos residen en el nodo local sin replicación.

# Ver los StorageClass de LocalPV disponibles
kubectl get storageclass | grep local

# LocalPV Hostpath: usa un directorio en el sistema de archivos del nodo
cat > pvc-localpv-hostpath.yaml << 'EOF'
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: datos-locales
  namespace: produccion
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: openebs-hostpath
  resources:
    requests:
      storage: 20Gi
EOF

kubectl apply -f pvc-localpv-hostpath.yaml

# Crear un StorageClass LocalPV personalizado con ruta específica
cat > storageclass-localpv-custom.yaml << 'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: localpv-datos
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: openebs.io/local
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
parameters:
  # Directorio base en el nodo donde se crearán los volúmenes
  basePath: "/mnt/datos-locales"
EOF

kubectl apply -f storageclass-localpv-custom.yaml

Jiva: Almacenamiento Replicado

Jiva proporciona replicación síncrana entre nodos usando iSCSI.

# Instalar el operador de Jiva (si no está incluido en la instalación base)
helm install jiva openebs/jiva \
  --namespace openebs \
  --create-namespace

# Verificar que Jiva está corriendo
kubectl get pods -n openebs | grep jiva

# Crear un StorageClass de Jiva con 3 réplicas
cat > storageclass-jiva.yaml << 'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: jiva-replicado
provisioner: jiva.csi.openebs.io
allowVolumeExpansion: true
parameters:
  cas-type: "jiva"
  policy: "jiva-policy-default"
EOF

kubectl apply -f storageclass-jiva.yaml

# Crear un JivaVolumePolicy para configurar el número de réplicas
cat > jiva-policy.yaml << 'EOF'
apiVersion: openebs.io/v1alpha1
kind: JivaVolumePolicy
metadata:
  name: jiva-policy-default
  namespace: openebs
spec:
  replicaSC: openebs-hostpath
  target:
    replicationFactor: 3
    resources:
      requests:
        memory: 250Mi
        cpu: 250m
      limits:
        memory: 500Mi
        cpu: 500m
  replica:
    resources:
      requests:
        memory: 250Mi
        cpu: 250m
      limits:
        memory: 1Gi
        cpu: 500m
EOF

kubectl apply -f jiva-policy.yaml

cStor: Motor de Almacenamiento Avanzado

cStor ofrece características avanzadas como snapshots, clones y thin provisioning usando ZFS a nivel de usuario.

# Instalar el operador de cStor
helm install cstor openebs/cstor \
  --namespace openebs \
  --create-namespace

kubectl get pods -n openebs | grep cstor

# Identificar los discos disponibles en los nodos
kubectl get blockdevices -n openebs

# Crear un CStorPoolCluster con los discos identificados
cat > cspc.yaml << 'EOF'
apiVersion: cstor.openebs.io/v1
kind: CStorPoolCluster
metadata:
  name: cstor-disk-pool
  namespace: openebs
spec:
  pools:
    # Pool en el primer nodo worker
    - nodeSelector:
        kubernetes.io/hostname: "worker-01"
      dataRaidGroups:
        - blockDevices:
            - blockDeviceName: "blockdevice-abc123"
      poolConfig:
        dataRaidGroupType: "stripe"  # stripe, mirror, raidz
    # Pool en el segundo nodo worker
    - nodeSelector:
        kubernetes.io/hostname: "worker-02"
      dataRaidGroups:
        - blockDevices:
            - blockDeviceName: "blockdevice-def456"
      poolConfig:
        dataRaidGroupType: "stripe"
    # Pool en el tercer nodo worker
    - nodeSelector:
        kubernetes.io/hostname: "worker-03"
      dataRaidGroups:
        - blockDevices:
            - blockDeviceName: "blockdevice-ghi789"
      poolConfig:
        dataRaidGroupType: "stripe"
EOF

kubectl apply -f cspc.yaml

# Verificar el estado del pool
kubectl get cspc -n openebs
kubectl get cspi -n openebs  # CStorPoolInstance por nodo

# Crear un StorageClass de cStor
cat > storageclass-cstor.yaml << 'EOF'
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
  name: cstor-3-replicas
provisioner: cstor.csi.openebs.io
allowVolumeExpansion: true
parameters:
  cas-type: cstor
  cstorPoolCluster: cstor-disk-pool
  replicaCount: "3"
EOF

kubectl apply -f storageclass-cstor.yaml

Mayastor: Almacenamiento NVMe

Mayastor es el motor más moderno de OpenEBS, diseñado para discos NVMe con latencias ultrabajas.

# Habilitar hugepages en los nodos (requerido por Mayastor)
echo 'vm.nr_hugepages = 1024' >> /etc/sysctl.d/99-mayastor.conf
sysctl -p /etc/sysctl.d/99-mayastor.conf

# Verificar hugepages
grep HugePages /proc/meminfo

# Instalar Mayastor
helm install mayastor openebs/mayastor \
  --namespace mayastor \
  --create-namespace \
  --set etcd.replicaCount=3

# Verificar los nodos de almacenamiento (DiskPools)
kubectl get diskpools -n mayastor

# Crear un DiskPool en un nodo
cat > diskpool.yaml << 'EOF'
apiVersion: openebs.io/v1beta2
kind: DiskPool
metadata:
  name: pool-worker-01
  namespace: mayastor
spec:
  node: worker-01
  disks:
    - uring:///dev/nvme0n1  # Disco NVMe usando io_uring
EOF

kubectl apply -f diskpool.yaml

# Crear StorageClass de Mayastor
cat > storageclass-mayastor.yaml << 'EOF'
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: mayastor-nvme
parameters:
  ioTimeout: "30"
  protocol: nvmf
  repl: "3"  # Número de réplicas NVMe-oF
provisioner: io.openebs.csi-mayastor
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: Immediate
EOF

kubectl apply -f storageclass-mayastor.yaml

Instantáneas y Backups

# Instalar el VolumeSnapshot controller (si no está instalado)
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/main/client/config/crd/snapshot.storage.k8s.io_volumesnapshotclasses.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/main/client/config/crd/snapshot.storage.k8s.io_volumesnapshotcontents.yaml
kubectl apply -f https://raw.githubusercontent.com/kubernetes-csi/external-snapshotter/main/client/config/crd/snapshot.storage.k8s.io_volumesnapshots.yaml

# Crear un VolumeSnapshotClass para cStor
cat > snapshot-class-cstor.yaml << 'EOF'
kind: VolumeSnapshotClass
apiVersion: snapshot.storage.k8s.io/v1
metadata:
  name: cstor-snapshot-class
driver: cstor.csi.openebs.io
deletionPolicy: Delete
EOF

kubectl apply -f snapshot-class-cstor.yaml

# Tomar una instantánea de un PVC
cat > volumesnapshot.yaml << 'EOF'
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: snapshot-datos-app
  namespace: produccion
spec:
  volumeSnapshotClassName: cstor-snapshot-class
  source:
    persistentVolumeClaimName: datos-locales
EOF

kubectl apply -f volumesnapshot.yaml
kubectl get volumesnapshots -n produccion

Ajuste de Rendimiento

# Verificar las métricas de rendimiento de los volúmenes cStor
kubectl get cstorvolumes -n openebs
kubectl describe cstorvolume <volume-name> -n openebs

# Ver las estadísticas de E/S de un volumen
kubectl exec -n openebs <cstor-target-pod> -- \
  cat /proc/$(pgrep iscsit)/io

# Para LocalPV, verificar el rendimiento con fio
kubectl run fio-test --image=ljishen/fio --restart=Never -- \
  fio --name=randwrite --ioengine=libaio --iodepth=16 \
  --rw=randwrite --bs=4k --direct=1 --size=1G \
  --numjobs=1 --filename=/datos/test

# Configurar prioridad de I/O para pods críticos
cat >> pod-spec.yaml << 'EOF'
  priorityClassName: system-cluster-critical
EOF

Solución de Problemas

PVC en estado Pending:

# Verificar eventos del PVC
kubectl describe pvc <nombre-pvc> -n <namespace>

# Verificar que el StorageClass existe
kubectl get storageclass

# Ver el estado de los operadores de OpenEBS
kubectl get pods -n openebs

# Logs del CSI controller
kubectl logs -n openebs -l openebs.io/component-name=openebs-controller -f

Volumen Jiva en estado Degraded:

# Ver el estado de las réplicas
kubectl get jivavolumes -n openebs

# Verificar conectividad iSCSI entre los nodos
iscsiadm -m session

# Reiniciar el target iSCSI
kubectl delete pod -n openebs -l openebs.io/component=jiva-controller

Conclusión

OpenEBS ofrece flexibilidad sin igual al proporcionar múltiples motores de almacenamiento para diferentes casos de uso: LocalPV para máximo rendimiento con datos locales, Jiva para replicación sencilla, cStor para características avanzadas, y Mayastor para entornos NVMe de ultra-baja latencia. Su naturaleza completamente containerizada lo hace fácil de instalar y operar, especialmente en entornos donde no hay un sistema de almacenamiento externo disponible.