Volúmenes persistentes en Azure Kubernetes Service

Esta semana te estuve contando cómo se utilizan los volúmenes en Kubernetes, en el escenario más simple con EmptyDir. Hoy voy a hablarte de los volúmenes persistentes y voy a utilizar Azure Kubernetes Service como plataforma de ejemplo.

¿Qué es un volumen persistente?

Se trata de un tipo de volumen pensado para el almacenamiento de datos que tienen un ciclo de vida diferente al del pod. Estos pueden crearse y eliminarse como un objeto independiente, lo cual significa que podemos mantener los datos antes y después de la existencia de la aplicación que los utiliza.

Tipos de volúmenes disponibles para AKS

En Azure, estos volúmenes persistentes pueden ser de dos tipos:

  • Azure Disks: solo pueden ser montados por un único pod.
  • Azure Files: se montan a través de SMB 3.0 y si que pueden ser montados por múltiples pods.

Ambos tipos soportan tanto la versión Standard como Premium de Azure Storage. Por lo tanto, la elección de un modo u otro será dependiendo de la concurrencia que necesites.

Tipos de volúmenes disponibles en AKS

Crear un volumen persistente

Vamos a seguir con el ejemplo del artículo anterior, que es el mismo que utilicé para explicar el funcionamiento de los volúmenes en Docker, sobre una base de datos postgres. Vamos a ir creando paso a paso los recursos de Kubernetes que necesitamos para crear y asociar un volumen persistente a nuestro pod. Para ello es importante que tengas en cuenta la siguiente imagen, donde verás todos los recursos que son necesario para la creación e integración de un volumen persistente:

Volumen persistente

1. StorageClass

Lo primero que necesitamos es un recurso del tipo StorageClass. AKS por defecto tiene dos clases creadas para nosotros:

  • default: utiliza el tipo Standard de Azure Storage y crea un Azure Disk, que son de los que solo pueden ser montados por un único pod. La política de retención establecida es que cuando el volumen se elimine el Azure Disk también será eliminado.
  • managed-premium: utiliza el tipo Premium y tiene las mismas condiciones que el anterior.

Una forma sencilla de comprobarlo es accediendo al Dashboard de Kubernetes a través del siguiente comando:

#Connect to Kubernetes Dashboard
az aks browse --name ${AKS_NAME} --resource-group ${RESOURCE_GROUP}

#if you don't have access yet
kubectl create clusterrolebinding kubernetes-dashboard -n kube-system --clusterrole=cluster-admin --serviceaccount=kube-system:kubernetes-dashboard

En el apartado Storage Classes verás que ya existen los dos y las características que tienen:

Kubernetes Dashboard – Storage Classes

Si no se especifica una Storage Class para un volumen se utiliza el llamado default.

Nota: Si no tienes un clúster de AKS en este artículo te cuento cómo crearlo.

2. PersistentVolumeClaim

Una vez que tenemos una Storage Class, necesitamos un recurso llamado PersistentVolumeClaim que hará de pegamento entre el pod, la clase y el volumen:

#persistent-volume-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: azure-managed-disk
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: managed-premium
  resources:
    requests:
      storage: 5Gi

En este recurso se especifica el modo de acceso al volumen, la clase que se va a utilizar y el tamaño que se solicita, en este caso de 5GB.

Para crear el recurso puedes hacerlo a través del siguiente comando:

kubectl apply -f persistent-volume-claim.yaml

Si accedes de nuevo al dashboard de Kubernetes verás que en el apartado Persistent Volumes tendrás un nuevo volumen con la configuración que acabas de lanzar.

Kubernetes Dashboard – Persistent Volumes

También puedes ver esta información a través del siguiente comando:

kubectl get pv
kubectl get pv

Un dato importante es que si no especificas nada el tipo de retención será Delete, lo cual significa que cuando borres este objeto el volumen creado también se eliminará. Tal y como afirma la documentación oficial, si la información almacenada en el volumen es importante es recomendable utilizar el modo Retain para que el volumen no sea eliminado, sino que se mantenga y puedas de manera manual recuperar los datos. Para tener un ejemplo más completo, vamos a modificar la política del que acabamos de crear a través del siguiente comando:

#Change the reclaim policy from Delete to Retain
kubectl patch pv <your-pv-name> -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}'
#List again to see the changes
kubectl get pv

A través de kubectl patch he cambiado el valor de persistentVolumeReclaimPolicy a Retain. Si vuelves a listar los volúmenes persistentes verás que ahora tiene como reclaim policy Retain:

Cambiado el tipo de politica a Retain

3. Pod con el volumen persistente

El último paso sería la creación del pod asociado al volumen persistente que has creado. Siguiendo el ejemplo del artículo anterior quedaría de la siguiente manera:

#pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: mypostgres-pv
spec:
  containers:
  - name: postgres
    image: postgres
    volumeMounts:
    - name: postgres-data
      mountPath: /var/lib/postgresql/data
      subPath: postgres
  volumes:
  - name: postgres-data
    persistentVolumeClaim:
      claimName: azure-managed-disk

Como ves, el formato es el mismo que en el artículo anterior solo que en la sección volumes, en lugar de utilizar emptyDir, uso persistentVolumeClaim y el nombre del claim que acabas de crear (azure-managed-disk). Por otro lado, en el caso de los volúmenes persistentes es necesario indicar un subPath para postgres, porque la ruta donde estamos montando el volumen tiene el directorio lost+found y este se queja de que la carpeta no está vacía, por lo que el pod no arrancará correctamente. Ejecuta el siguiente comando para crear el pod:

kubectl apply -f pod.yaml

Podrás ver en el dashboard que el pod se ha creado correctamente y que tiene el volumen persistente asociado.

Kubernetes Dashboard – Pod creado con el volumen persistente asociado

Lo último que te queda por probar es que todo esto funciona correctamente, al igual que hicimos en el articulo anterior. Accede al pod a través del siguiente comando:

kubectl exec -it mypostgres-pv -- /bin/bash

Ahora ejecuta lo siguiente para crear una nueva base de datos, una tabla y un registro:

#Create a postgress db
createdb -U postgres mydb

#Access to my postgress db
psql -U postgres mydb

#Create a table
CREATE TABLE products (id int, name varchar(100));

#Create a product into my table
INSERT INTO products (id, name) VALUES (1, 'Wheel');

#List products
SELECT * from products;

#Exit postgress client
\q

Del mismo modo, la prueba más sencilla sería matar el proceso de postgress dentro del pod para que este se reiniciara:

#list processes
ps aux
#kill postgres (PID 1)
kill 1

Esto hará que salgas del terminal y necesites volver a conectarte. Tanto el dashboard como con kubectl get pods verás que el valor de restarts ahora está a 1, lo cual significa que el pod tuvo que reiniciarse. Si no tuviera un volumen persistente los datos se habrían perdido pero, gracias a este artículo, puedes volver a entrar en tu base de datos y comprobar que tu tabla y tu registro siguen ahí:

kubectl exec -it mypostgres-pv -- /bin/bash

#Access to my postgress db
psql -U postgres mydb

#List products
SELECT * from products;

La última prueba de fuego sería eliminar el pod:

kubectl delete pod mypostgres-pv

volver a crearlo:

kubectl apply -f pod.yaml

y comprobar que la base de datos continúa ahí, gracias a que el volumen no se eliminó al eliminar el primer pod, debido a la política Retain.

¡Saludos!