K8s + NFS (CentOS)
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.