Sobre el proyecto

pillar-csi es un controlador CSI de Kubernetes para clústeres bare-metal autoalojados. Toma zvols ZFS locales o volúmenes lógicos LVM en un nodo de almacenamiento dedicado y los exporta al resto del clúster mediante NVMe-oF/TCP, escribiendo directamente en el kernel a través de configfs en lugar de depender de SSH, demonios Python o CLIs de target externos. Explícitamente no es un sistema de archivos distribuido: no replica, distribuye en franjas ni agrupa almacenamiento entre nodos. La arquitectura consta de tres workloads. pillar-controller se ejecuta como un Deployment y reconcilia los CRD Pillar* con alcance de clúster. pillar-agent se ejecuta como un DaemonSet solo en nodos de almacenamiento y posee todas las escrituras en configfs del host. pillar-node se ejecuta en cada worker y gestiona el servicio CSI Node (conexión del iniciador, mkfs, bind-mount). Ambos DaemonSets usan hostNetwork para que el plano de datos NVMe-oF/TCP pueda enlazarse al espacio de nombres de red del host. La configuración es declarativa mediante CRD: PillarAgent localiza un agente de almacenamiento, PillarStore describe un pool de almacenamiento (nombre del pool ZFS, VG de LVM, configuración del backend), PillarProtocol describe la configuración del protocolo de red, y PillarStorageClass combina pool y protocolo en una StorageClass generada automáticamente. Un CRD interno PillarVolumeState registra el estado duradero para la recuperación ante fallos parciales de aprovisionamiento y el seguimiento de publicaciones; el controlador impone la exclusividad del modo de acceso CSI a partir de ese registro. Un elemento de diseño destacable es el fencing de operaciones obsoletas. Cada llamada al agente que cambia los recursos de un volumen lleva un token de fencing compuesto por el UID del estado del volumen (identidad del ciclo de vida) y un contador publicationGeneration incrementado mediante compare-and-swap. El agente mantiene marcas duraderas por volumen en el disco local del nodo de almacenamiento bajo /var/lib/pillar-csi/agent/generations/, montado como hostPath para que las marcas sobrevivan a reinicios y rearranques. Las solicitudes anteriores a la marca, de un ciclo de vida terminado o reemplazado, o que no lleven token, se rechazan con FAILED_PRECONDITION. El README señala una advertencia de actualización: desconectar todos los volúmenes antes de actualizar, ya que las versiones anteriores no registraban publicaciones, ciclos de vida ni generaciones, y no se proporciona ninguna capa de migración. El estado de node stage se registra bajo /var/lib/pillar-csi/node/ en el worker, escrito de forma atómica mediante archivo temporal, sync y rename. NodeUnstageVolume vuelve a leer el registro porque el CO no envía ni la capacidad del volumen ni el contexto del volumen en unstage. Las decisiones de desmontaje se delegan al Unmount idempotente del mounter, tratando los errores de sondeo de montajes corruptos (EIO, ENOTCONN, ESTALE, EACCES) como aún montados para que kubelet pueda reclamar pods cuyo sistema de archivos entró en apagado del kernel. Matriz compatible: ZFS zvol y LVM LV sobre NVMe-oF/TCP están disponibles; iSCSI está diseñado pero aún no disponible; NFS para datasets ZFS está diseñado pero aún no disponible. Las operaciones CSI incluyen CreateVolume, DeleteVolume, ControllerPublish/Unpublish, ControllerExpandVolume, NodeStage/Unstage, NodePublish/Unpublish, NodeExpandVolume, NodeGetVolumeStats, ValidateVolumeCapabilities y GetCapacity. Los modos de acceso son ReadWriteOnce, ReadWriteOncePod y ReadOnlyMany; los modos de volumen son Filesystem (ext4/xfs) y Block. La instalación se realiza mediante Helm. mTLS entre controller y agent es opcional (modo cert-manager o modo Secret proporcionado); el valor predeterminado es gRPC en texto plano. Se requiere Kubernetes 1.24 o posterior. Los nodos de almacenamiento necesitan los módulos del kernel nvmet y nvmet_tcp; los nodos worker necesitan nvme_tcp y nvme_fabrics; los init-containers ejecutan modprobe al arrancar. El README incluye un quickstart con ejemplos de YAML de CRD, solución de problemas mediante kubectl describe y logs estándar, y un procedimiento de recuperación detallado para volúmenes heredados atascados en ExportSpecMissing, que enfatiza decisiones explícitas del operador para bindAddress, port y aclEnabled en lugar de adivinar a partir de observaciones en tiempo de ejecución.