La mentalidad de los contenedores es que sus datos se pierden tras borrarse, así que los datos que necesitamos que no se pierdan, deberán ir en volumenes.
En caso de tener un Kubernetes desplegado en una Cloud, lo recomendable es utilizar el sistema de estos, pero si tenemos nuestro propio sistema, nos tendremos que apañar con lo que podamos.
El más sencillo de todos es asociar el volumen a una carpeta compartida por NFS.
Explicación
Lo primero a tener en cuenta es que compartiremos una carpeta de un servidor utilizando NFS, cualquier nodo que despliegue el pod, montará la unidad con NFS, en caso de que el servidor NFS se caiga o no sea posible conectar con él, la carpeta del contenedor dejará de funcionar, así que nuestro pod funcionará, no llegará a caerse por defecto, pero no funcionará correctamente.
Tener en cuenta esto es muy importante, ya que si nuestro pod está bien configurado y Kubernetes detecta esta caída del servicio, es posible que intente volver a desplegar un nuevo pod para matar al anterior, pero este nuevo pod fallará por no poder conectar al servidor NFS, y así una y otra vez.
El otro punto importante es que NFS únicamente comparte la unidad, no se encarga de replicas, así que, si los datos del servidor se pierden, se perdería todo, con lo que sería altamente recomendable tener un sistema de copias de seguridad.
Este artículo está planteado para ser una base de cómo preparar un servidor NFS y desplegar un Nginx que lo utilice, para ello utilizaré servidores CentOS y un Kubernetes.
1- NFS Server
Necesitamos un servidor que haga de servidor, así que instalamos todo.
dnf install nfs-utils nfs4-acl-tools -y systemctl enable --now nfs-server firewall-cmd --permanent --add-service=nfs firewall-cmd --permanent --add-service=rpc-bind firewall-cmd --permanent --add-service=mountd firewall-cmd --reload
Ahora creamos una carpeta y la compartimos
mkdir -p /mnt/nfsShare/storage1 vi /etc/exports
En CentOS 8 es necesario añadir el no_root_squash para poder escribir en la carpeta compartida sin problemas.
/mnt/nfsShare/storage1 192.168.1.0/24(rw,sync,no_root_squash)
Exportamos la unidad
exportfs -rav
Podemos mostrar la lista de todas las carpetas compartidas.
exportfs -v
2- NFS Client en nodos
En cada nodo de Kubernetes hay que instalar las aplicaciones necesarias para que puedan montar carpetas compartidas, si un nodo no lo tiene, al revisar los logs del pod, veremos un error montando la partición.
dnf install nfs-utils nfs4-acl-tools -y
3- Desplegar Nginx con NFS
Lo primero será preparar el PersistentVolume donde se indicará la ruta hacia el servidor, la ruta y el tamaño del storage, nfs-pv.yaml:
apiVersion: v1 kind: PersistentVolume metadata: name: nfs-storage spec: storageClassName: storage-nfs capacity: storage: 1Gi accessModes: - ReadWriteMany nfs: server: nfsServer.domain.intranet path: "/mnt/nfsShare/storage1"
Lo siguiente será conectar el PersistentVolumeClaim que utilizaremos en el despliegue, nfs-pvc-nginx.yaml:
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-nginx spec: storageClassName: storage-nfs accessModes: - ReadWriteMany resources: requests: storage: 1Gi
Utilizando el ejemplo de la documentación oficial, con la pequeña modificación de que se anclará su carpeta de publicación a la carpeta compartida por NFS, nginx-deployment.yaml:
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-nfs-deployment spec: selector: matchLabels: app: nginx replicas: 2 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 volumeMounts: - name: nfs-storage mountPath: "/usr/share/nginx/html" volumes: - name: nfs-storage persistentVolumeClaim: claimName: nfs-nginx
Una vez tenemos los 3 ficheros, los aplicamos.
kubectl create -f nfs-pv.yaml kubectl create -f nfs-pvc-nginx.yaml kubectl create -f nginx-deployment.yaml
Podemos comprobar que el PersistentVolume esté creado.
kubectl get pv
Resultado:
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE nfs-storage 1Gi RWX Retain Bound default/nfs-nginx storage-nfs 106s
El PersistentVolumeClaim.
kubectl get pvc
Resultado:
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE nfs-nginx Bound nfs-storage 1Gi RWX storage-nfs 2m5s
Y finalmente, los pods.
kubectl get pods -o wide -l app=nginx
Resultado:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-nfs-deployment-559d6cb454-9h6vg 1/1 Running 0 28s 10.244.93.4 temp101 <none> <none> nginx-nfs-deployment-559d6cb454-gzrgd 1/1 Running 0 28s 10.244.173.200 temp102 <none> <none>
Para hacer la prueba, podemos acceder dentro de uno de los pods, crear un index.html y confirmar que podemos verlo.
kubectl exec -it nginx-nfs-deployment-559d6cb454-9h6vg -- bash cd /usr/share/nginx/html echo "Hello NFS" > index.html curl localhost
Lo que nos devolverá el contenido del index.html
Si modificamos este fichero desde el host de NFS, veremos el cambio inmediatamente.
Final
Partiendo de este ejemplo, podremos desplegar cualquier contenedor conectando sus volumenes a un NFS, así no nos tendremos que preocupar de replicas entre diferentes nodos o pérdida de datos.
Aun así, hay que tener en cuenta los problemas de rendimiento que puede tener la red.