Cuando quieres almacenamiento persistente en k3s y no quieres atarte al disco local de un nodo, lo habitual es montar un NAS y delegar en NFS. El reto es que Kubernetes, por defecto, no sabe “negociar” con un servidor NFS: necesitas un componente que traduzca las peticiones de almacenamiento (PVCs) en carpetas NFS reales.
Ahí entra NFS Subdir External Provisioner. Es un pequeño controlador que actúa como fábrica de PersistentVolumes: cada vez que creas un PVC, él crea la carpeta en el NAS y el PV correspondiente de forma automática. Tú solo pides almacenamiento; él se encarga del resto.
Requisitos previos
Antes de tocar k3s, asegúrate de que el NAS está listo:
- Servicio NFS habilitado. En el NAS (Synology, QNAP, TrueNAS, etc.) activa el servicio NFS. Apunta la ruta de la carpeta compartida, por ejemplo
/volume1/cluster-datos. - Permisos correctos. La carpeta compartida debe permitir lectura/escritura a las IPs de todos los nodos del clúster. Muy importante: en Synology, el ajuste de squash tiene que estar en No mapping o Map root to admin, porque Kubernetes monta como root y, si el NAS “aplana” el root a
nobody, los pods no van a poder escribir.
Paso 1: Instalar Helm
Para instalar el provisioner de forma limpia usaremos Helm, el gestor de paquetes de Kubernetes. Si ya lo tienes, salta al paso 2. Si no, instálalo en el nodo master:
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
Paso 2: Instalar el NFS Provisioner
Añade el repo oficial, actualiza e instala el provisioner. Cambia 192.168.1.50 por la IP de tu NAS y /volume1/cluster-datos por la ruta real de tu carpeta compartida:
# Añadir el repositorio de Helm
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
# Actualizar la lista de charts
helm repo update
# Instalar el provisioner
helm install nfs-proveedor-nas nfs-subdir-external-provisioner/nfs-subdir-external-provisioner \
--set nfs.server=192.168.1.50 \
--set nfs.path=/volume1/cluster-datos \
--set storageClass.name=nas-storage \
--set storageClass.defaultClass=false
Lo que le estamos diciendo a k3s, en una sola línea, es: “instala este programa, conéctalo al NAS en esa IP y ruta, y crea una nueva StorageClass llamada nas-storage”. El flag defaultClass=false es importante: hace que la StorageClass de k3s por defecto (local-path) siga siendo la principal. Si quieres que nas-storage sea la default, cámbialo a true, pero perderás la local.
Verifica que la “fábrica” está lista:
kubectl get storageclass
Deberías ver listadas dos: local-path (la de k3s) y nas-storage (la que acabas de crear).
Paso 3: El cambio mental importante
En el aprovisionamiento dinámico te saltas el paso de escribir el YAML del PV a mano. El provisioner que acabas de instalar lo hace por ti en cuanto detecta un PVC que solicita su StorageClass. Así que pasamos directo a crear el PVC.
Paso 4: Crear el PVC
Crea un archivo pvc-nas-dinamico.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-mi-wordpress
spec:
accessModes:
- ReadWriteMany
storageClassName: nas-storage
resources:
requests:
storage: 5Gi
ReadWriteMany es clave cuando trabajas con NFS: significa que el PVC puede ser montado por varios pods a la vez, lo que te permite mover pods entre nodos sin que se bloqueen por un ReadWriteOnce que ya tiene otro nodo.
Aplica el archivo:
kubectl apply -f pvc-nas-dinamico.yaml
¿Qué pasa por detrás?
Tres cosas, casi en tiempo real:
kubectl get pvcmuestra el PVC en estadoBound(vinculado).kubectl get pvlista un PV nuevo con un nombre largo del estilopvc-12345678-abcd..., creado sin que escribieras una sola línea de su manifiesto.- En el NAS, dentro de
/volume1/cluster-datos/, aparece una carpeta real con un nombre del tipodefault-pvc-mi-wordpress-pvc-XXXXXX.
Si todo eso ocurre, el provisioner está funcionando.
Paso 5: Crear un Pod que consuma el PVC
Para cerrar el ciclo, monta el PVC en un Pod. Si ese Pod muere y se levanta en otro nodo, se conectará a la misma carpeta del NAS sin que tengas que hacer nada.
Crea un archivo pod-nas.yaml:
apiVersion: v1
kind: Pod
metadata:
name: nginx-nas
spec:
containers:
- name: webserver
image: nginx:alpine
volumeMounts:
- mountPath: /usr/share/nginx/html
name: datos-nas
volumes:
- name: datos-nas
persistentVolumeClaim:
claimName: pvc-mi-wordpress
Aplica el archivo:
kubectl apply -f pod-nas.yaml
Lo que acabas de conseguir
- Configuración única (Paso 2): el provisioner queda instalado apuntando a la IP raíz del NAS.
- Para cada nueva app (Pasos 4 y 5): solo tienes que crear un PVC pidiendo espacio a
nas-storagey un Pod que lo monte. k3s se encarga de crear subcarpetas organizadas en el NAS y generar los PV transparentemente.
Resultado: persistencia externa, orden en el NAS y aplicaciones 100% movibles entre nodos. Una vez que lo tienes funcionando, añadir almacenamiento a una app nueva cuesta tres líneas de YAML.