Cómo desplegar WordPress en K3s

Seguimos en la senda de los microservicios o contenedores con Kubernetes, esta vez mostrando cómo desplegar WordPress en K3s. Recordad que recientemente vimos cómo crear un entorno de Kubernetes en alta disponibilidad con Ubuntu y K3s.

Elaborar esta entrada me ha dado un poco de guerra, porque por una cosa u otra no conseguía realizar el despliegue de forma correcta, al final la clave es fijarse que los espacios de los YAML sean los correctos. Además, una nota más, al final de la entrada os dejo la fuente de la que he sacado la mayoría de la información, por que sí, yo al igual que todos, no obtengo la información de forma mágica.

Al igual que otras veces, voy a utilizar el laboratorio de pruebas creado en mi proveedor de confianza Clouding.io, que os recomiendo.

Logo de Kubernetes

Desplegar WordPress en K3s

Recordar que en la entrada, que os he comentado en el primer párrafo, además de desplegar el entorno con K3s, también habilitamos el gestor de paquetes HELM; para después realizar la instalación de  Ingress Nginx, pieza fundamental para que el entorno tenga visibilidad de forma externa.

Instalar Cert-Manager

Nos interesa que los proyectos web, que despleguemos en el entorno, puedan utilizar HTTPS con su correspondiente certificado. Para ello vamos a utilizar Cert-Manager, para crear y administrar certificados SSL, utilizando los suministrados desde la iniciativa Let’s Encrypt

Añadimos el repositorio Jetstack, para que nos suministre el «chart» que necesitamos:

helm repo add jetstack https://charts.jetstack.io

Y actualizamos:

helm repo update

Ahora sí, instalamos:

helm install \
cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--version v1.7.1 \
--set installCRDs=true

Ficheros en Github

Antes de nada, os comento que todos los YAML de esta entrada los podéis encontrar en un repositorio en Github que he creado para la ocasión: github.com/davidochobits/wordpress-in-k3s, se aceptan sugerencias.

Evidentemente los ficheros YAML los tenéis que adaptar a vuestras necesidades. En este ejemplo he creado un wordpress llamado laboratoriowp.bitsandlinux.com, que ahora mismo ya podéis ver funcionando. Aunque, en el proyecto he incorporado un servicio de mysql, diría que en entornos productivos, sería mucho mejor utilizar una conexión a un servidor mysql dedicado. Ya que crear un servicio mysql por cada wordpress es una locura.

Preparar los secretos para el despliegue

Tranquilos que en esta parte no necesitaremos ninguna máquina enigma. Simplemente, para no añadir en los YAML las contraseñas «a pelo», podemos utilizar un fichero «kustomization.yaml», que contendrá la información confindencial, sobre las contraseñas y las bases de datos a utilizar en el proyecto.

En este caso, con el contenido:

secretGenerator:
- name: mysql-password
  literals:
  - password=contrasea2022
- name: mysql-user
  literals:
  - username=userwp
- name: mysql-user-password
  literals:
  - passworduser=contrasea2022
- name: mysql-database
  literals:
  - database=multitenant_wpp

A continuación, utilizando el parámetro «-k«, generaremos los secretos desde el fichero:

kubectl apply -k .

Con el resultado, en mi caso:

secret/mysql-database-4f74mgddt5 created
secret/mysql-password-6kffcc6hhg created
secret/mysql-user-4t5mcf8dkm created
secret/mysql-user-password-fkbf7g7th9 created

Creación de volúmenes

Los volúmenes en Kubernetes tienen dos tipos, el llamado PersistentVolume y el PersistentVolumeClaim. Un PersistentVolume (PV) es una pieza de almacenamiento en el clúster que ha sido aprovisionada por un administrador o aprovisionada dinámicamente mediante clases de almacenamiento.

En cambio, Un PersistentVolumeClaim (PVC) es un tipo de almacenamiento, como pods, que consume recursos en Kubernetes, como memoria y CPU, que pueden reclamar el tamaño y el modo de acceso para crear volúmenes con modos de acceso específicos. Estos se pueden configurar como acceso de lectura y escritura o de solo lectura.

Crear volúmenes para MySQL

Primero vamos a crear un PersistentVolume llamado «msyql-pv-volume.yaml», con esta información:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv2
spec:
  storageClassName: do-block-storage
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/var/lib/mysql1"

A continuación, creamos un fichero llamado «mysql-pv-claim.yaml» para definir un PersistentVolumeClain, como sigue:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim2
spec:
  storageClassName: do-block-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

En ambos casos he definido un espacio de almacenamiento de 1 GB, aquí cada cual según sus necesidades.

Una vez hecho esto, desplegamos los volúmenes:

kubectl apply -f mysql-pv-volume.yaml 
kubectl apply -f mysql-pv-claim.yaml

Con el resultado:

persistentvolume/mysql-pv2 created
persistentvolumeclaim/mysql-pv-claim2 created

Podemos ver la información de los volúmenes creados con:

kubectl get pv

Y vemos la información obtenida:

NAME           CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM
mysql-pv2      1Gi        RWO            Retain           Bound    default/mysql-pv-claim2

Crear volúmenes para WordPress

Ahora nos toca hacer mismo pero para los volúmenes que utilizará WordPress. Primero creamos un fichero llamado «wordpress-pv-volume.yaml», donde vamos a definir el PV, con el contenido:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: wordpress-pv2
spec:
  storageClassName: do-block-storage
  capacity: 
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/var/www1"

A continuación, creamos el PVC, con el nombre «wordpress-pv-claim.yaml», con el contenido:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: wordpress-pv-claim2
spec:
  storageClassName: do-block-storage
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

Y los creamos:

kubectl apply -f wordpress-pv-volume.yaml 
kubectl apply -f wordpress-pv-claim.yaml

Con el resultado, una vez aplicados:

persistentvolume/wordpress-pv2 created
persistentvolumeclaim/wordpress-pv-claim2 created

Listamos todos los volúmenes creados:

NAME            CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM
mysql-pv2       1Gi        RWO            Retain           Bound    default/mysql-pv-claim2
wordpress-pv2   1Gi        RWO            Retain           Bound    default/wordpress-pv-claim2

Crear el servicio MySQL

Ahora vamos a crear el fichero YAML, llamado «mysql-service.yaml», donde además de definir diferentes parámetros del servicio, vamos a utilizar los secretos que hemos creado antes, así que debemos tenerlos a mano. Podemos ver los secretos con el comando «kubectl describe secret«.

El contenido del fichero es el siguiente:

apiVersion: v1
kind: Service
metadata:
  name: mysql-wp1
spec:
  ports:
    - port: 3306
  selector:
    app: wordpress1
    tier: mysql1
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql-wp1
spec:
  selector:
    matchLabels:
      app: wordpress1
      tier: mysql1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress1
        tier: mysql1
    spec:
      containers:
      - image: mysql:latest
        name: mysql1
        env:
        - name: MYSQL_ROOT_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-password-6kffcc6hhg
              key: password
        - name: MYSQL_USER
          valueFrom:
            secretKeyRef:
              name: mysql-user-4t5mcf8dkm
              key: username
        - name: MYSQL_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-user-password-fkbf7g7th9
              key: passworduser
        - name: MYSQL_DATABASE
          valueFrom:
            secretKeyRef:
              name: mysql-database-4f74mgddt5
              key: database
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: persistent-storage1
          mountPath: /var/lib/mysql1
      volumes:
      - name: persistent-storage1
        persistentVolumeClaim:
          claimName: mysql-pv-claim2

Verificamos que todo esta OK, y así podemos aplicar:

kubectl apply -f mysql-service.yaml

Con el resultado:

service/mysql-wp1 created
deployment.apps/mysql-wp1 created

Crear el servicio para WordPress

Ahora toca hacer lo propio para definir el servicio de WordPress, esto lo haremos creando el fichero «wordpress-service.yaml». Y lo mismo de antes, debemos tener a manos los secretos.

apiVersion: v1
kind: Service
metadata:
  name: wordpress1
spec:
  ports:
    - port: 80
  selector:
    app: wordpress1
    tier: web1
  type: LoadBalancer
 
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: wordpress1
spec:
  selector:
    matchLabels:
      app: wordpress1
      tier: web1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: wordpress1
        tier: web1
    spec:
      containers:
      - image: wordpress:php8.1-apache
        name: wordpress1
        env:
        - name: WORDPRESS_DB_HOST
          value: mysql-wp1:3306
        - name: WORDPRESS_DB_PASSWORD
          valueFrom:
            secretKeyRef:
              name: mysql-user-password-fkbf7g7th9
              key: passworduser
        - name: WORDPRESS_DB_USER
          valueFrom:
            secretKeyRef:
              name: mysql-user-4t5mcf8dkm
              key: username
        - name: WORDPRESS_DB_NAME
          valueFrom:
            secretKeyRef:
              name: mysql-database-4f74mgddt5
              key: database
        ports:
        - containerPort: 80
          name: wordpress1
        volumeMounts:
        - name: persistent-storage2
          mountPath: /var/www1/html
      volumes:
      - name: persistent-storage2
        persistentVolumeClaim:
          claimName: wordpress-pv-claim2

Revisamos todo y aplicamos:

kubectl apply -f wordpress-service.yaml

Con el resultado:

service/wordpress1 created
deployment.apps/wordpress1 created

Con el comando «kubectl get svc«, podemos ver los servicios desplegados:

Mostramos los servicios desplegados

Utilizar letsencrypt para desplegar WordPress

En esta parte vamos a configurar el certificado SSL para nuestro proyecto, utilizando Let’s Encrypt. En el fichero que vamos a crear debemos definir nuestro correo electrónico:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata: 
  name: wp-prod-issuer1
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: davidochobits@colaboratorio.net
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
      - http01:
          ingress:
            class: nginx

El fichero lo guardamos con el nombre «wp_production_issuer.yaml»

Ejecutamos:

kubectl apply -f wp_production_issuer.yaml

Con el resultado:

clusterissuer.cert-manager.io/wp-prod-issuer created

Configurar Ingress con HTTPS y despliegue

Ahora que ya hemos configurado los certificados SSL, es hora de definir el registro para el Ingress de Nginx. Aquí tenemos que definir el dominio que vamos a utilizar, en mi caso laboratoriowp.bitsandlinux.com. Aquí importante, tenemos que tener este registro creado en nuestro proveedor habitual, en el apartado de DNS. Creamos el fichero «wordpress_ingress.yaml», con toda la información adaptada a nuestras necesidades:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: wordpress1
  annotations:
    kubernetes.io/ingress.class: "nginx"
    cert-manager.io/cluster-issuer: "wp-prod-issuer1"
spec:
  rules:
  - host: laboratoriowp.bitsandlinux.com
    http:
     paths:
     - path: "/"
       pathType: Prefix
       backend:
         service:
           name: wordpress1
           port:
             number: 80
  tls:
  - hosts:
    - laboratoriowp.bitsandlinux.com
    secretName: wordpress-tls1

Y desplegamos:

ingress.networking.k8s.io/wordpress1 created

Configuración de WordPress via web

Si todo ha ido bien, al ir a la web y poner el dominio configurado, tendríamos que poder acceder al nuevo wordpress.

Acceso para instalar WordPress

Una vez configurado todo, podemos ver el resultado:

Aspecto de la web una vez configurada

Conclusiones

Hemos visto como desplegar un WordPress con un MySQL utilizando tanto PersistenVolume como PersistentVolumeClaim.  Cada maestrillo tiene su librillo y siempre hay diferentes caminos para llegar a una misma meta, depende de nuestro ingenio, habilidad y creatividad. En cualquier caso al hacerlo de esta manera, utilizamos diferentes piezas disponibles en Kubernetes y K3s.

Fuentes consultadas

Sesamedisk.com – Deploy WordPress on K8s