Guía paso a paso para instalar WordPress con MariaDB y PVC Longhorn en Kubernetes

Introducción

En el vertiginoso mundo de la gestión de contenedores, Kubernetes ha emergido como la plataforma líder para la orquestación de aplicaciones en entornos de producción. Dentro del vasto ecosistema de Kubernetes, la gestión de bases de datos es una consideración crucial para cualquier aplicación que busque escalabilidad, confiabilidad y persistencia. En esta guía, exploraremos cómo desplegar WordPress, uno de los sistemas de gestión de contenido más populares, junto con MariaDB, una potente base de datos relacional, todo ello en un entorno Kubernetes. Además, utilizaremos Longhorn para gestionar el almacenamiento persistente, asegurando así la integridad de nuestros datos incluso en caso de fallos en los nodos del clúster.

Pasos a seguir:

  1. Despliegue de MariaDB utilizando un PVC Longhorn: Configuraremos una instancia de MariaDB en nuestro clúster Kubernetes, utilizando Longhorn para gestionar el almacenamiento persistente de la base de datos.
  2. Configuración de WordPress para usar MariaDB: Una vez que MariaDB esté en funcionamiento, procederemos a configurar WordPress para que utilice esta base de datos en lugar de la base de datos integrada.
  3. Despliegue de WordPress: Finalmente, desplegaremos una instancia de WordPress en nuestro clúster Kubernetes, asegurándonos de que esté configurada correctamente para interactuar con la base de datos MariaDB que acabamos de configurar.

Acerca de Longhorn:

Longhorn es una solución de almacenamiento distribuido y persistente para Kubernetes, diseñada para ser fácil de usar y altamente confiable. Proporciona funciones avanzadas de replicación y recuperación ante desastres, lo que lo convierte en una opción ideal para entornos de producción que requieren almacenamiento persistente para sus aplicaciones.

Persistencia de datos para mariadb en longhorn

La persistencia de los datos es fundamental para garantizar la integridad y disponibilidad de las aplicaciones. El siguiente manifiesto crea un PersistentVolumeClaim (PVC), el cual esta asociado a un StorageClass llamado longhorn. A continuación vamos a crear los dos PVC uno para mariadb y otro para wordpress.

 

Manifiesto PVC mariadb

Creamos un archivo llamado: 01-mariadb-pvc.yaml

kind: PersistentVolumeClaim
metadata:
name: mariadb-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: longhorn

Variables del manifiesto

  • apiVersion: v1: Indica que este manifiesto sigue la especificación de la API v1 de Kubernetes.
  • kind: PersistentVolumeClaim: Define que este objeto es un PersistentVolumeClaim, que se utiliza para solicitar almacenamiento persistente en Kubernetes.
  • metadata: Contiene metadatos asociados con el PVC, como el nombre.
    • name: mariadb-pvc: Es el nombre asignado al PersistentVolumeClaim.
  • spec: Define las especificaciones del PVC, incluidos los requisitos de acceso y recursos.
    • accessModes: Especifica los modos de acceso al volumen. En este caso, «ReadWriteOnce» significa que el volumen solo puede ser montado en un único nodo a la vez y puede ser leído y escrito.
    • resources: Define los recursos solicitados para el volumen.
      • requests: Especifica los recursos mínimos necesarios para el volumen.
        • storage: 5Gi: Solicita al menos 5 gigabytes de almacenamiento para el PVC.
    • storageClassName: longhorn: Indica la clase de almacenamiento que se utilizará para provisionar este volumen. En este caso, se utiliza la clase de almacenamiento «longhorn».

Manifieso PVC wordpress

Vamos a crear un archivo (manifiesto) llamado 02-wordpress-pvc.yaml para crear el PVC llamado wordpress-pvc en el StorageClass longhorn.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-pvc-protege
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 2Gi
  storageClassName: longhorn

Variables del manifiesto

  • apiVersion: v1: Indica que este manifiesto sigue la especificación de la API v1 de Kubernetes.
  • kind: PersistentVolumeClaim: Define que este objeto es un PersistentVolumeClaim, que se utiliza para solicitar almacenamiento persistente en Kubernetes.
  • metadata: Contiene metadatos asociados con el PVC, como el nombre.
    • name: wordpress-pvc: Es el nombre asignado al PersistentVolumeClaim.
  • spec: Define las especificaciones del PVC, incluidos los requisitos de acceso y recursos.
    • accessModes: Especifica los modos de acceso al volumen. En este caso, «ReadWriteOnce» significa que el volumen solo puede ser montado en un único nodo a la vez y puede ser leído y escrito.
    • resources: Define los recursos solicitados para el volumen.
      • requests: Especifica los recursos mínimos necesarios para el volumen.
        • storage: 2Gi: Solicita al menos 5 gigabytes de almacenamiento para el PVC.
    • storageClassName: longhorn: Indica la clase de almacenamiento que se utilizará para provisionar este volumen. En este caso, se utiliza la clase de almacenamiento «longhorn».

Comandos:

  • Verificar que el StorageClass longhorn este creado
 # k get storageclasses.storage.k8s.io 
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
longhorn (default) driver.longhorn.io Delete Immediate true 9d

Con este comando verificamos que el StorageClass longhorn esta creado y podemos usarlo para aprovicionar los PVC.

  • Comando para aplicar el manifiesto 01-mariadb-pvc.yaml
# k apply -f 01-mariadb-pvc.yaml 
persistentvolumeclaim/mariadb-pv-protege created
  • Verificación:
# k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mariadb-pvc Bound pvc-4597d384-bfb6-4c7b-8aee-444227f06051 5Gi RWO longhorn 18s

  • Comando para aplicar el manifiesto 02-wordpress-pvc.yaml
# k apply -f 02-wordpress-pvc.yaml 
persistentvolumeclaim/wordpres-pvc created

El comando anterior aplica el manifiesto.

  • Verificación:
# k get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mariadb-pvc Bound pvc-4597d384-bfb6-4c7b-8aee-444227f06051 5Gi RWO longhorn 5m14s
wordpress-pvc Bound pvc-51b45fef-3fd2-4391-b735-09f3570865ff 2Gi RWO longhorn 6s

La verificación nos muestra que tenemos los dos PVC creados.

Creación de un configmap para mariadb

¿Qué son ConfigMaps?

Antes de profundizar en cómo utilizar ConfigMaps con MariaDB, es importante comprender qué son exactamente.

Los objetos ConfigMaps nos permiten almacenar datos de configuración en forma de pares clave-valor. Estos datos pueden incluir variables de entorno, archivos de configuración o cualquier otro tipo de información necesaria para nuestras aplicaciones.

En nuestro despliegue, utilizamos un ConfigMap para almacenar la URL de la base de datos MariaDB. Esto nos permite separar la configuración de la aplicación del código fuente, lo que facilita la gestión y la portabilidad de nuestras implementaciones, vamos a crear un manifiesto llamado: 03-mariadb-configmap.yaml, con el siguiente contenido.

apiVersion: v1
kind: ConfigMap
metadata:
  name: mariadb-configmap
data:
  database_url: mariadb-internal-service

Variables del manifiesto

  • apiVersion: Especifica la versión de la API de Kubernetes que estás utilizando.
  • kind: Define el tipo de recurso de Kubernetes, en este caso, un ConfigMap (Mapa de Configuración).
  • metadata: Contiene metadatos sobre el ConfigMap, incluyendo su nombre.
  • data: Esta sección contiene pares de clave-valor que representan los datos de configuración. En este caso, hay un par de clave-valor:
  • database_url: Esta clave almacena la URL o el nombre de host de tu servicio MariaDB (mariadb-internal-service).

Comandos:

  • Aplicamos el manifiesto 03-mariadb-configmap.yaml
# k apply -f 03-mariadb-configmap.yaml 
configmap/mariadb-configmap created
  • Verificamos:
k get configmaps  -n blog 
NAME                DATA   AGE
kube-root-ca.crt    1      3d16h
mariadb-configmap   1      50s

Secrets

Los Secrets son objetos en Kubernetes diseñados para almacenar datos sensibles, como contraseñas, tokens de acceso o claves de cifrado, de forma segura. Los Secrets están codificados en base64 para garantizar la confidencialidad de los datos almacenados.

Descripción del archivo de Secret:

El archivo de Secret que estamos analizando se utiliza para almacenar la contraseña de root de MariaDB de forma segura. El nombre del Secret es mariadb-secret y su tipo es Opaque, lo que indica que se trata de un secreto genérico sin estructura específica.

El valor de la contraseña de root de MariaDB se encuentra en la sección data del Secret y está codificado en base64. Aunque la contraseña está codificada, es importante recordar que la codificación base64 no es un método seguro para almacenar contraseñas en producción. En un entorno de producción real, se recomienda utilizar herramientas de gestión de secretos más robustas, como Kubernetes Vault o herramientas externas de gestión de secrets.

Vamos a crear ahora el manifiesto 04-mariadb-secret.yaml

apiVersion: v1
kind: Secret
metadata:
    name: mariadb-secret
type: Opaque
data:
  # Valor obtenido: echo -n 'secret'|base64
  mariadb-root-password:  c2VjcmV0
  • apiVersion: v1: Indica que este recurso Secret pertenece a la versión 1 de la API de Kubernetes.
  • kind: Secret: Define el tipo de recurso como un Secret, que se utiliza para almacenar datos sensibles de forma segura en un clúster de Kubernetes.
  • metadata: Contiene metadatos sobre el Secret, incluyendo su nombre (mariadb-secret).
  • type: Opaque: Especifica el tipo de Secret. Opaque se refiere a un secreto genérico sin una estructura específica de datos.
  • data: Esta sección contiene los datos sensibles codificados en base64. En este caso, hay un solo campo:
    mariadb-root-password: Contiene la contraseña de root de MariaDB, que ha sido codificada en base64.

Comandos:

  • Aplicamos el manifiesto 04-mariadb-secret.yaml
# k apply -f 04-mariadb-secret.yaml 
secret/mariadb-secret created
  • Verificamos:
# k get secrets
NAME TYPE DATA AGE
mariadb-secret Opaque 1 31s
  • Vamos a ir un paso mas alla y ver toda la info del manifiesto aplicado utilizando el modificador describe
# k describe secret
Name:         mariadb-secret
Namespace:    blog
Labels:       
Annotations:  

Type:  Opaque

Data
====
mariadb-root-password:  15 bytes

Vamos ahora a crear un service para mariadb

Los Service son un recurso fundamental que actúa como un balanceador de carga y un punto de acceso estable para los Pods que ejecutan una aplicación en un clúster. Básicamente, un Service expone una aplicación que se ejecuta en uno o más Pods y permite que otras partes de la aplicación o servicios externos se comuniquen con ella de manera predecible y confiable, independientemente de en qué nodo del clúster se estén ejecutando los Pods.

Vamos a crear el manifiesto 05-mariadb-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: mariadb-internal-service
spec:
  selector:
    app: mariadb
  ports:
    - protocol: TCP
      port: 3306
      targetPort: 3306
  clusterIP: None

Este manifiesto de Kubernetes define un servicio (Service) llamado mariadb-internal-service que proporciona acceso interno a un servicio de base de datos MariaDB dentro de un clúster de Kubernetes. Aquí está la explicación detallada:

  • apiVersion: v1: Indica que este recurso Service pertenece a la versión 1 de la API de Kubernetes.
  • kind: Service: Define el tipo de recurso como un Service, que se utiliza para exponer aplicaciones dentro de un clúster de Kubernetes para que otras aplicaciones puedan comunicarse con ellas.
  • metadata: Contiene metadatos sobre el Service, incluyendo su nombre (mariadb-internal-service).
  • spec: Especifica las características del Service.
  • selector: Define qué Pods se van a seleccionar para el servicio. En este caso, el Service seleccionará los Pods que tienen el label app: mariadb.
  • ports: Lista los puertos que el Service expone.
    protocol: TCP: Indica que se utiliza el protocolo TCP para la comunicación.
  • port: 3306: Es el puerto en el que escucha el Service.
  • targetPort: 3306: Es el puerto en el que los contenedores de los Pods seleccionados están escuchando.
  • clusterIP: None: Esto especifica que el Service no tiene una dirección IP interna en el clúster y solo se puede acceder internamente desde el clúster.

Este Service se puede utilizar para permitir que otras aplicaciones dentro del clúster de Kubernetes se comuniquen con el servicio de base de datos MariaDB utilizando el nombre del servicio (definido previamente en configmap) mariadb-internal-service y el puerto especificado (3306).

Comandos

  • Aplicamos el manifiesto:
# k apply -f 05-mariadb-service.yaml 
service/mariadb-internal-service created
  • Verificamos:
# k get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mariadb-internal-service ClusterIP None <none> 3306/TCP 4s

 

Vamos a definir ahora un service para wordpress.

Creamos el archivo 06-wordpress-service.yaml

apiVersion: v1
kind: Service
metadata:
  name: wordpress
spec:
  selector:
    app: wordpress
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP #default
      nodePort: 30007
  type: NodePort

Este manifiesto de Kubernetes define un servicio (Service) llamado protege que expone una aplicación de WordPress en un clúster de Kubernetes utilizando el tipo de servicio NodePort. Aquí está la explicación detallada:

apiVersion: v1: Indica que este recurso Service pertenece a la versión 1 de la API de Kubernetes.
kind: Service: Define el tipo de recurso como un Service, que se utiliza para exponer aplicaciones dentro de un clúster de Kubernetes para que otras aplicaciones puedan comunicarse con ellas.
metadata: Contiene metadatos sobre el Service, incluyendo su nombre (protege).
spec: Especifica las características del Service.
selector: Define qué Pods se van a seleccionar para el servicio. En este caso, el Service seleccionará los Pods que tienen el label app: wordpress.
ports: Lista los puertos que el Service expone.
port: 80: Es el puerto en el que el Service escuchará las solicitudes de red.
targetPort: 80: Es el puerto en el que los contenedores de los Pods seleccionados están escuchando.
protocol: TCP: Especifica el protocolo utilizado para la comunicación. En este caso, TCP es el valor predeterminado.
nodePort: 30007: Este es el puerto de nodo que se asignará al Service. Los servicios NodePort hacen que el Service sea accesible en cada nodo del clúster en la dirección IP del nodo y el puerto especificado.

Comandos:

  • Aplicamos el manifiesto:
k apply -f 06-wordpress-service.yaml
service/protege created
  • Verificamos:
# k get service 
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
mariadb-internal-service ClusterIP None <none> 3306/TCP 6m29s
wordpress NodePort 10.99.169.96 <none> 80:30007/TCP 76s

 

Vamos a crear ahora el deployment para mariadb

Este manifiesto de Kubernetes define un Deployment para crear y gestionar un conjunto de Pods que ejecutan una instancia de MariaDB en un clúster de Kubernetes.
Creamos ahora el manifiesto 07-mariadb-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb-deployment
spec: # specification for deployment resource
  replicas: 1
  selector:
    matchLabels:
      app: mariadb
  template: # blueprint for Pod
    metadata:
      labels:
        app: mariadb # service will look for this label
    spec: # specification for Pod
      containers:
      - name: mariadb
        image: mariadb
        ports:
        - containerPort: 3306 #default one
        env:
        - name: MARIADB_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mariadb-secret
              key: mariadb-root-password
        - name: MARIADB_DATABASE
          value: wordpress
        volumeMounts:
        - name: mariadb-pvc
          mountPath: /var/lib/mysql
      volumes:
      - name: mariadb-pvc
        persistentVolumeClaim:
          claimName: mariadb-pvc


  • apiVersion: apps/v1: Indica que este recurso Deployment pertenece a la versión 1 de la API de aplicaciones de Kubernetes.
  • kind: Deployment: Define el tipo de recurso como un Deployment, que se utiliza para gestionar la creación y escalado de aplicaciones en Kubernetes.
  • metadata: Contiene metadatos sobre el Deployment, incluyendo su nombre (mariadb-deployment).
  • spec: Especifica las características del Deployment.
    • replicas: 1: Indica que se debe crear una sola réplica del Pod de MariaDB. Esto significa que habrá un solo Pod de MariaDB ejecutándose.
    • selector: Define cómo se seleccionarán los Pods que serán gestionados por este Deployment. En este caso, selecciona los Pods que tienen el label app: mariadb.
    • template: Define el modelo para crear los Pods que serán gestionados por este Deployment.
      • metadata: Contiene metadatos sobre el Pod template, incluyendo sus labels.
      • spec: Especifica las características del Pod.
        • containers: Lista los contenedores que se ejecutarán en el Pod.
          • name: mariadb: Define el nombre del contenedor como «mariadb».
          • image: mariadb: Especifica la imagen del contenedor que se utilizará para ejecutar la instancia de MariaDB.
          • ports: Lista los puertos que el contenedor expone.
            • containerPort: 3306: Es el puerto en el que la instancia de MariaDB dentro del contenedor está escuchando.
          • env: Lista las variables de entorno que se pasarán al contenedor.
            • name: MARIADB_ROOT_PASSWORD: Nombre de la variable de entorno que representa la contraseña de root de MariaDB.
              • valueFrom: Indica que el valor de la variable de entorno se obtendrá de una referencia a un Secret.
                • secretKeyRef: Especifica el nombre del Secret (mariadb-secret) y la clave (mariadb-root-password) de donde se obtendrá el valor.
            • name: MARIADB_DATABASE: Nombre de la variable de entorno que representa el nombre de la base de datos de MariaDB.
              • value: wordpress: Valor de la variable de entorno, que en este caso es «wordpress».
          • volumeMounts: Lista los puntos de montaje que se utilizarán para montar volúmenes en el contenedor.
            • name: mariadb-pvc: Nombre del volumen que se montará en el contenedor.
            • mountPath: /var/lib/mysql: Ruta dentro del contenedor donde se montará el volumen.
        • volumes: Lista los volúmenes que se utilizarán en el Pod.
          • name: mariadb-pvc: Nombre del volumen.
            • persistentVolumeClaim: Especifica el nombre de la reclamación de volumen persistente (mariadb-pvc) que se utilizará para este volumen.

Este Deployment creará un solo Pod de MariaDB, utilizando la imagen de MariaDB especificada, con la contraseña de root y el nombre de la base de datos configurados a través de variables de entorno, y montará un volumen persistente para almacenar los datos de la base de datos en el directorio /var/lib/mysql.

Comandos:

  • Aplicamos el manifiesto 07-mariadb-deployment.yaml
# k apply -f 07-mariadb-deployment.yaml 
deployment.apps/mariadb-deployment created

 

  • Verificamos:
# k apply -f 07-mariadb-deployment.yaml 
deployment.apps/mariadb-deployment created

 

Vamos a crear ahora un despliegue para wordpress

apiVersion: apps/v1
kind: Deployment
metadata:
name: wordpress-deployment
spec: # specification for deployment resource
replicas: 1
selector:
matchLabels:
app: wordpress
template: # blueprint for Pod
metadata:
labels:
app: wordpress
spec: # specification for Pod
containers:
- name: wordpress
image: wordpress:latest 
ports:
- containerPort: 80
env:
- name: WORDPRESS_DB_HOST
valueFrom:
configMapKeyRef:
name: mariadb-configmap
key: database_url
- name: WORDPRESS_DB_PASSWORD
valueFrom:
secretKeyRef:
name: mariadb-secret
key: mariadb-root-password
- name: WORDPRESS_DB_USER
value: root
- name: WORDPRESS_DEBUG
value: "1"
volumeMounts:
- name: wordpress-pvc
mountPath: /var/www/html/
volumes:
- name: wordpress-pvc
persistentVolumeClaim:
claimName: wordpress-pvc

 

  • apiVersion: apps/v1: Indica que este recurso Deployment pertenece a la versión 1 de la API de aplicaciones de Kubernetes.
  • kind: Deployment: Define el tipo de recurso como un Deployment, que se utiliza para gestionar la creación y escalado de aplicaciones en Kubernetes.
  • metadata: Contiene metadatos sobre el Deployment, incluyendo su nombre (wordpress-deployment).
  • spec: Especifica las características del Deployment.
    • replicas: 1: Indica que se debe crear una sola réplica del Pod de WordPress. Esto significa que habrá un solo Pod de WordPress ejecutándose.
    • selector: Define cómo se seleccionarán los Pods que serán gestionados por este Deployment. En este caso, selecciona los Pods que tienen el label app: wordpress.
    • template: Define el modelo para crear los Pods que serán gestionados por este Deployment.
      • metadata: Contiene metadatos sobre el Pod template, incluyendo sus labels.
      • spec: Especifica las características del Pod.
        • containers: Lista los contenedores que se ejecutarán en el Pod.
          • name: wordpress: Define el nombre del contenedor como «wordpress».
          • image: wordpress:latest: Especifica la imagen del contenedor que se utilizará para ejecutar la aplicación de WordPress. En este caso, utiliza la última versión de la imagen de WordPress disponible en el repositorio Docker oficial.
          • ports: Lista los puertos que el contenedor expone.
            • containerPort: 80: Es el puerto en el que el contenedor de WordPress escuchará las solicitudes de red.
          • env: Lista las variables de entorno que se pasarán al contenedor.
            • name: WORDPRESS_DB_HOST: Nombre de la variable de entorno que representa la dirección del host de la base de datos de WordPress.
              • valueFrom: Indica que el valor de la variable de entorno se obtendrá de una referencia a un ConfigMap.
                • configMapKeyRef: Especifica el nombre del ConfigMap (mariadb-configmap) y la clave (database_url) de donde se obtendrá el valor.
            • name: WORDPRESS_DB_PASSWORD: Nombre de la variable de entorno que representa la contraseña de la base de datos de WordPress.
              • valueFrom: Indica que el valor de la variable de entorno se obtendrá de una referencia a un Secret.
                • secretKeyRef: Especifica el nombre del Secret (mariadb-secret) y la clave (mariadb-root-password) de donde se obtendrá el valor.
            • name: WORDPRESS_DB_USER: Nombre de la variable de entorno que representa el usuario de la base de datos de WordPress.
              • value: root: Valor de la variable de entorno, que en este caso es «root».
            • name: WORDPRESS_DEBUG: Nombre de la variable de entorno que activa el modo de depuración de WordPress.
              • value: "1": Valor de la variable de entorno, que en este caso es «1» para activar el modo de depuración.
          • volumeMounts: Lista los puntos de montaje que se utilizarán para montar volúmenes en el contenedor.
            • name: wordpress-pvc: Nombre del volumen que se montará en el contenedor.
            • mountPath: /var/www/html/: Ruta dentro del contenedor donde se montará el volumen.
        • volumes: Lista los volúmenes que se utilizarán en el Pod.
          • name: wordpress-pvc: Nombre del volumen.
            • persistentVolumeClaim: Especifica el nombre de la reclamación de volumen persistente (wordpress-pvc) que se utilizará para este volumen.

 

Comandos

  • Aplicamos el manifiesto 07-wordpress-deployment.yaml
# k apply -f 07-mariadb-deployment.yaml 
deployment.apps/mariadb-deployment created
  • Verificamos:
# k get deployments.apps mariadb-deployment 
NAME                 READY   UP-TO-DATE   AVAILABLE   AGE
mariadb-deployment   1/1     1            0           3m22s

 

Por fin podemos ir a wordpress…

Para esto abrimos el navegador y tipeamos http://IP_NODO_CUSTER:30007