Cómo utilizar Portworx Essentials para proporcionar almacenamiento persistente y distribuido a las aplicaciones desplegadas en Kubernetes

Javier Ramírez-Urea, arquitecto de soluciones en Hopla! Software

Hoy, os traemos este post sobre Portworx Essentials. En él, vamos a hablar de cómo utilizar esta herramienta para ofrecer almacenamiento persistente y distribuido a las aplicaciones desplegadas en Kubernetes

El caso que os traemos es desplegar un simple WordPress. Veremos cómo el almacenamiento persistente nos permite mover la base de datos, o el propio frontal de WordPress, a cualquier nodo.

Al tratarse de una versión gratuita, no tendremos acceso a algunas de las características de la versión empresarial, a parte de las diferencias de volumen. Por ello, os recomendamos consultar más información sobre este despliegue aquí

#Paso 1

El primer paso es parte de un cluster muy sencillo de Kubernetes. Para esta prueba desplegamos cuatro máquinas virtuales con Terraform y posteriormente lo realizamos con Kubernetes con nuestros playbooks Ansible

En unos minutos tenemos un cluster con un master y tres nodos worker. 

Nuestro despliegue Terraform prepara 25GB de disco en cada nodo worker. Estos discos son los que usaremos como dispositivo de bloques para que Portworx gestione como almacenamiento persistente en nuestro cluster. 

Utilizaremos un balanceador externo que redirija las peticiones al FQDN “wordpress.hoplalabs.local” a nuestro Ingress Controller desplegado en el cluster.

Para la instalación de WordPress usaremos un Chart de Bitnami, por lo que nuestro entorno cuenta con Helm ya instalado.

Partiendo de este entorno, revisamos la versión de Kubernetes. IMPORTANTE: será necesario para desplegar Portworx de forma apropiada.

$ kubectl get nodes

NAME         STATUS   ROLES    AGE     VERSION

kube-node1   Ready    master   10m     v1.18.2

kube-node2   Ready    <none>   7m45s   v1.18.2

kube-node3   Ready    <none>   5m21s   v1.18.2

Entramos en el portal de Portworx para generar un fichero de despliegue de la plataforma. 

Es un proceso muy sencillo que nos guía con sencillas preguntas sobre nuestra infraestructura subyacente. Con nuestras respuestas, el portal genera un fichero que podremos usar directamente.

Registro en Portworx Essentials para crear una cuenta en la plataforma Portworx Central y obtener un usuario de acceso: 

Una vez dentro, nos dirigimos a “Install and Run”.

Nos abrirá un entorno ”wizard” que nos guiará por las distintas opciones de plataforma, recopilando la información necesaria para desplegar Portworx en nuestra infraestructura. 

Esta herramienta es Spec Generator y nos permite generar los ficheros de despliegue completos, con todos los componentes y características necesarias.

La primera opción que debemos elegir es qué tipo de plataforma vamos a desplegar. 

Podemos elegir entre Portworx Essentials y Portworx Enterprise. Para un entorno de demo, preproducción o desarrollo, recomendamos usar Portworx Essentials. Esta plataforma nos ayudará a entender y ver las características más importantes de Portworx.

Porworx Essentials nos permite gestionar un máximo de 500 volúmenes y 5TB de información. Además, acepta un máximo de 5 nodos, lo que supone un máximo de 1TB por nodo. Portworx Essentials se puede gestionar con un único cluster de Portwox, por lo que será recomendable usar Portworx Enterprise en entorno multi-tenant, por ejemplo.

Una vez seleccionamos Portworx Essentials, comienza la recogida de información de nuestro despliegue. Lo primero que necesitamos saber es la versión de Kubernetes sobre la que se ejecutará la plataforma y la versión de Portworx que desplegaremos.

#Paso 2

En este paso se configura si el despliegue se realizará en alguna nube o en nuestro centro de datos.

Seleccionaremos cómo queremos que Portworx gestione los discos. En este ejemplo, dejaremos que Portworx busque el almacenamiento disponible y lo adquiera para persistencia.

Nos preguntará, además, por la generación de un disco de journal para gestionar las sincronizaciones y evitar cuellos de botella. En este caso, dejamos que Portworx lo genere por nosotros.

El último punto de esta fase se refiere a la disposición de un entorno de KeyValue. 

NOTA: Portworx puede usar un entorno externo (recomendable) o bien generar el suyo propio. En el caso de permitir la generación de su propia base de datos, es recomendable usar un disco específico. En este caso, dado que se trata de una demo rápida, desplegaremos el entorno sin este recurso específico.

#Paso 3

En este paso podremos especificar los interfaces que usaremos para la red de datos, separando la gestión de la sincronización de los bloques. En este entorno de demo que estamos usando sólo tenemos una interfaz, por lo que podemos dejar estas opciones en “auto”.

#Paso 4

En el último paso debemos especificar sobre qué infraestructura estamos trabajando. De esta forma, Portwrox puede integrarse con la plataforma existente y creará el fichero de despliegue, teniendo en cuenta cualquier particularidad que pudiera ser relevante en el proceso.

Si nuestras imágenes se encuentran en un registro interno o necesitamos configurar variables u opciones adicionales, este será el momento de hacerlo.

Cuando pulsemos “Next”, nos aparecerá un acuerdo de licencia para poder usar la plataforma que vamos a desplegar. El proceso estará completo.

Una vez finalicemos esta guía, el portal generará un fichero de despliegue.

Este fichero puede guardarse para posteriores usos, pudiendo identificarlo por nombre y añadirle etiquetas.

Copiaremos la línea de despliegue. Esta línea variará de unas instalaciones a otras porque identifica unívocamente cada despliegue.

Aplicaremos entonces el despliegue en nuestro cluster *las capturas de pantalla en la demo corresponden a un despliegue anterior:

$ kubectl apply -f

https://install.portworx.com/2.5?mc=false&kbver=1.18.2&oem=esse&user=d4f15375-d0bb-11ea-a2c5-c24e499c7467&b=true&f=true&j=auto&c=px-cluster-a09d6d11-b585-424f-ad96-08dd5d07b079&stork=true&lh=true&st=k8s

service/portworx-service created

customresourcedefinition.apiextensions.k8s.io/volumeplacementstrategies.portworx.io created

serviceaccount/px-account created

clusterrole.rbac.authorization.k8s.io/node-get-put-list-role created

clusterrolebinding.rbac.authorization.k8s.io/node-role-binding created

namespace/portworx created

role.rbac.authorization.k8s.io/px-role created

rolebinding.rbac.authorization.k8s.io/px-role-binding created

secret/px-essential created

daemonset.apps/portworx created

service/portworx-api created

daemonset.apps/portworx-api created

serviceaccount/stork-account created

clusterrole.rbac.authorization.k8s.io/stork-role created

clusterrolebinding.rbac.authorization.k8s.io/stork-role-binding created

deployment.apps/stork created

storageclass.storage.k8s.io/stork-snapshot-sc created

service/stork-service created

configmap/stork-config created

serviceaccount/stork-scheduler-account created

clusterrole.rbac.authorization.k8s.io/stork-scheduler-role created

clusterrolebinding.rbac.authorization.k8s.io/stork-scheduler-role-binding created

deployment.apps/stork-scheduler created

serviceaccount/px-lh-account created

clusterrole.rbac.authorization.k8s.io/px-lh-role created

clusterrolebinding.rbac.authorization.k8s.io/px-lh-role-binding created

service/px-lighthouse created

deployment.apps/px-lighthouse created

configmap/autopilot-config created

serviceaccount/autopilot-account created

clusterrole.rbac.authorization.k8s.io/autopilot-role created

clusterrolebinding.rbac.authorization.k8s.io/autopilot-role-binding created

deployment.apps/autopilot created

service/autopilot created

Como vemos, el despliegue genera un número importante de recursos en el cluster. Se ejecutarán varios procesos en cada nodo para gestionar la sincronización y uso de los dispositivos de bloques.

Nuestra idea es usar el almacenamiento de Portworx como StorageClass para poder gestionar los volúmenes de forma dinámica.

Creamos entonces un recurso de tipo “StoraceClass”. Usamos “portwrx-sc” en este ejemplo:

$ cat<<EOF|kubectl create -f –  

kind: StorageClass

apiVersion: storage.k8s.io/v1

metadata:

  name: portworx-sc

provisioner: kubernetes.io/portworx-volume

parameters:

  repl: «1»

EOF

storageclass.storage.k8s.io/portworx-sc created

Una vez tenemos nuestro StorageClass creado, podemos proceder a desplegar WordPress. En este caso, usaremos Helm para realizar el despliegue de forma automatizada.

Para ello, añadimos el repositorio de Charts de Bitnami para la instalación: 

$ helm repo add bitnami https://charts.bitnami.com/bitnami

$ helm repo update

Ahora configuramos la instalación de WordPress. Para ello, revisamos las variables que tenemos a nuestro alcance en el Chart para modificar el comportamiento de WordPress (https://hub.helm.sh/charts/bitnami/wordpress). Ponemos atención fundamentalmente en las variables referentes al espacio de almacenamiento persistente de WordPress y MariaDB. Recordemos que tenemos tan sólo 25GB de disco por nodo en nuestro entorno.

$ helm install wordpress \

 –set global.storageClass=portworx-sc \

 –set persistence.size=1Gi \

 –set mariadb.master.persistence.size=2Gi \

 –set ingress.enabled=true \

 –set ingress.hostname=wordpress.hoplalabs.local \

 –set wordpressUsername=admin \

 –set wordpressPassword=password \

  bitnami/wordpress

NAME: wordpress

LAST DEPLOYED: Thu Aug 27 14:58:43 2020

NAMESPACE: default

STATUS: deployed

REVISION: 1

NOTES:

** Please be patient while the chart is being deployed **

Your WordPress site can be accessed through the following DNS name from within your cluster:

    wordpress.default.svc.cluster.local (port 80)

To access your WordPress site from outside the cluster follow the steps below:

1. Get the WordPress URL and associate WordPress hostname to your cluster external IP:

   export CLUSTER_IP=$(minikube ip) # On Minikube. Use: `kubectl cluster-info` on others K8s clusters

   echo «WordPress URL: http://wordpress.hoplalabs.local/»

   echo «$CLUSTER_IP  wordpress.hoplalabs.local» | sudo tee -a /etc/hosts

2. Open a browser and access WordPress using the obtained URL.

3. Login with the following credentials below to see your blog:

  echo Username: admin

  echo Password: $(kubectl get secret –namespace default wordpress -o jsonpath=»{.data.wordpress-password}» | base64 –decode)

Accedemos al FQDN de publicación (en DNS y balanceado a las IP de los nodos de publicación de nuestro cluster con el puerto de nuestro Ingress-Controller) y observamos que WordPress está funcionando correctamente.

Si nos fijamos en los PerstentVolumeClaims creados en el proceso de instalación de WordPress, observamos lo siguiente:

$ kubectl get pvc

NAME                       STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE

data-wordpress-mariadb-0   Bound    pvc-34bb23a6-57d3-4ab7-943d-92f00d5dad39   2Gi        RWO            portworx-sc    1h

wordpress                  Bound    pvc-f6b492c8-7791-42d0-8d85-b393ad598d15   1Gi        RWO            portworx-sc    1h

Los PVCs están asociados al recurso StorageClass que hemos creado usando Portworx.

Creamos una entrada en el blog accediendo como “admin” para poder comprobar la persistencia en caso de conmutación del servicio.

Vamos a ver qué ocurre ahora si conmutamos los datos. Observamos en qué nodos están los pods desplegados:

$ kubectl get pod -o wide

NAME                                                              READY   STATUS    RESTARTS   AGE     IP            NODE      NOMINATED NODE   READINESS GATES

nginx-controller-nginx-ingress-controller-b645f985d-7kg6c         1/1     Running   0          92m     10.10.13.8    worker3   <none>           <none>

nginx-controller-nginx-ingress-controller-default-backend-65ngs   1/1     Running   0          4h29m   10.10.13.2    worker3   <none>           <none>

wordpress-bfd5f4c68-z7cnt                                         1/1     Running   0          10m     10.10.9.198   worker2   <none>           <none>

wordpress-mariadb-0                                               1/1     Running   0          4h5m    10.10.13.7    worker3   <none>           <none>

Lo más sencillo en esta situación para asegurar que MariaDB se irá a otro nodo, será hacer un “drain” en el nodo worker3, por ejemplo. Veamos qué sucede:

$ kubectl drain  worker3 –ignore-daemonsets

node/worker3 cordoned

WARNING: ignoring DaemonSet-managed Pods: kube-system/calico-node-ps5f8, kube-system/kube-proxy-tnjqw, kube-system/portworx-api-wfhs4, kube-system/portworx-sk2xz

evicting pod default/nginx-controller-nginx-ingress-controller-default-backend-65ngs

evicting pod default/nginx-controller-nginx-ingress-controller-b645f985d-7kg6c

evicting pod kube-system/autopilot-58db5f4dbb-2kd9x

evicting pod default/wordpress-mariadb-0

evicting pod kube-system/stork-f4799f469-m6k6h

evicting pod kube-system/stork-scheduler-8d85c5b46-gsnc4

pod/stork-f4799f469-m6k6h evicted

pod/nginx-controller-nginx-ingress-controller-default-backend-65ngs evicted

pod/stork-scheduler-8d85c5b46-gsnc4 evicted

pod/autopilot-58db5f4dbb-2kd9x evicted

pod/nginx-controller-nginx-ingress-controller-b645f985d-7kg6c evicted

pod/wordpress-mariadb-0 evicted

node/worker3 evicted

Como es de esperar, el Pod de MariaDB se mueve a otro nodo. En este caso, worker1 recibe la carga.

$ kubectl get pod -o wide

NAME                                                              READY   STATUS              RESTARTS   AGE   IP             NODE      NOMINATED NODE   READINESS GATES

nginx-controller-nginx-ingress-controller-b645f985d-l5qnn         1/1     Running             0          95s   10.10.11.138   worker1   <none>           <none>

nginx-controller-nginx-ingress-controller-default-backend-46qc4   1/1     Running             0          96s   10.10.11.137   worker1   <none>           <none>

wordpress-bfd5f4c68-z7cnt                                         0/1     Running             5          23h   10.10.9.198    worker2   <none>           <none>

wordpress-mariadb-0                                               0/1     ContainerCreating   0          37s   <none>         worker1   <none>           <none>

Tras unos segundos, el proceso está de nuevo en ejecución. Esta vez la base de datos se encuentra en el nodo worker1.

$ kubectl get pod -o wide

NAME                                                              READY   STATUS    RESTARTS   AGE     IP             NODE      NOMINATED NODE   READINESS GATES

nginx-controller-nginx-ingress-controller-b645f985d-l5qnn         1/1     Running   0          3m31s   10.10.11.138   worker1   <none>           <none>

nginx-controller-nginx-ingress-controller-default-backend-46qc4   1/1     Running   0          3m32s   10.10.11.137   worker1   <none>           <none>

wordpress-bfd5f4c68-z7cnt                                         1/1     Running   6          23h     10.10.9.198    worker2   <none>           <none>

wordpress-mariadb-0                                               1/1     Running   0          2m33s   10.10.11.140   worker1   <none>           <none>

provision@kube1:~$ 

Este es un ejemplo muy sencillo, con el que podemos ver cómo de sencillo resulta usar Portworx Essentials para gestionar nuestro almacenamiento persistente en Kubernetes. 

Portworx nos permite garantizar los datos en un cluster e incluso entre varios distintos; siendo además una herramienta fundamental cuando estos clusters se encuentran en diferentes localizaciones o entornos cloud.

La gestión de la disponibilidad, número de réplicas de bloque, sincronización, snapshots, etc, en Portworx queda fuera del alcance de este sencillo post pero esperamos que os haya sido de utilidad y os anime a usar esta potente herramienta.

Puedes descargarte el resultado final en este link

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *