Desplegar una aplicación web con Minikube

0
6895
Creative cloud background with gears. Eps10 vector for your design

Indice de contenidos

Introducción

En este tutorial veremos un ejemplo práctico de cómo desplegar una aplicación web básica en Kubernetes que para almacenar los datos se comunica con una base de datos MySql también desplegada en el clúster.

Se puede leer una introducción a Kubernetes en este tutorial.

Para simplificar el tutorial y no hacer una instalación de Kubernetes desde cero, tarea que no es especialmente sencilla, vamos a usar Minikube, que está muy bien para hacer pruebas en entornos de desarrollo, pero no es recomendable poner en producción.

Podemos ver otro tipo de instalaciones locales de Kubernetes en

Entorno

Este tutorial está escrito usando el siguiente entorno:

  • Hardware: MacBook Pro 15’ (2,5 GHz Intel Core i7, 16GB DDR3)
  • Sistema operativo: macOS Mojave 10.14.1
  • Versiones:
    • Docker: 18.09.0
    • Minikube: v0.30.0
    • VirtualBox 5.2.22 r126460 (Qt5.6.3).

Aplicación utilizada

Para el tutorial voy a usar de ejemplo una aplicación propia de gestión de catálogos de cursos que desarrollé para probar un pequeño framework que implementé. La tengo alojada en GitHub y se puede obtener con:

git clone https://github.com/diyipol/framework.git

Creación del despliegue con la base de datos

Antes que nada, debemos arrancar Minikube:

minikube start --cpus 4 --memory 7680

Una vez que tengamos minikube arrancado vamos a crear el PersistentVolume con el PersistentVolumeClaim al que se conectará la base de datos. Para no perder la información cada vez que paremos minikube, debemos crear el volumen en alguno de los siguientes directorios:

  • /data
  • /var/lib/minikube
  • /var/lib/docker

Creamos catalogocursos-mysql-pv.yaml:

kind: PersistentVolume
apiVersion: v1
metadata:
  name: catalogocursos-mysql-pv-volume
  labels:
    type: local
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/data/catalogocursos-mysql-pv"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: catalogocursos-mysql-pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

Seguidamente desplegamos en kubernetes:

kubectl create -f catalogocursos-mysql-pv.yaml

Mostramos la información del PersistentVolume creado:

kubectl describe pv

Name:            catalogocursos-mysql-pv-volume
Labels:          type=local
Annotations:     pv.kubernetes.io/bound-by-controller=yes
Finalizers:      [kubernetes.io/pv-protection]
StorageClass:    manual
Status:          Bound
Claim:           default/catalogocursos-mysql-pv-claim
Reclaim Policy:  Retain
Access Modes:    RWO
Capacity:        5Gi
Node Affinity:   
Message:         
Source:
    Type:          HostPath (bare host directory volume)
    Path:          /data/catalogocursos-mysql-pv
    HostPathType:  
Events:            

Lo siguiente que vamos a hacer es crear el servicio catalogocursos-mysql-svc.yaml:

apiVersion: v1
kind: Service
metadata:
    name: catalogocursos-mysql-service
spec:
    type: NodePort
    selector:
        app: catalogocursos-mysql-service
    ports:
      - name: my-sql
        port: 3306

Establecemos «type: NodePort» para poder conectarnos a la base de datos desde algún cliente fuera del clúster.

Por último creamos el despliegue catalogocursos-mysql-deployment.yaml para que se conecte con el servicio y el PersistentVolumeClaim anteriormente creados:

apiVersion: apps/v1 
kind: Deployment
metadata:
  name: catalogocursos-mysql-deployment
spec:
  selector:
    matchLabels:
      app: catalogocursos-mysql-service
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: catalogocursos-mysql-service
    spec:
      containers:
      - image: mysql:5.7.23
        name: mysql
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: root
        - name: MYSQL_DATABASE
          value: cursos_autentia
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: catalogocursos-mysql-pv-claim

Los desplegamos:

kubectl create -f catalogocursos-mysql-svc.yaml

kubectl create -f catalogocursos-mysql-deployment.yaml

Como tiene que descargar la imagen, puede que tarde un poco. Podemos ver el estado con:

kubectl get pods 

Cuando ya esté en estado «Running» podemos pedirle a minikube la url para conectarnos a la base de datos desde cualquier cliente externo:

minikube service catalogocursos-mysql-service --url

Ya con cualquier cliente de base de datos como DBeaver podremos acceder a la base de datos en la url y puerto que nos devuelva. En este ejemplo en particular, para que la aplicación catálogo de cursos funcione, tenemos que pasar el parche db_schema.sql que se encuentra en la carpeta sql del proyecto, teniendo en cuenta que la base de datos ya tiene que estar creada.

Creación del despliegue con la aplicación web

Lo primero que vamos a hacer es generar la imagen docker con el war desplegado en el tomcat para usar en kubernetes. Generamos primero un war con el perfil kubernetes. En este caso, en esta aplicación, el perfil cambia la url de conexión de base de datos, para que pueda conectar con la que acabamos de crear de forma que la url de conexión quede del tipo:

jdbc:mysql://catalogocursos-mysql-service:3306/cursos_autentia

Generamos el war:

mvn clean package -Pkubernetes

Ahora creamos el Dockerfile con el que tenemos que construir la imagen.

FROM tomcat:9.0.13-jre8-alpine
MAINTAINER Pablo Betancor Lugo

ADD ./cursosautentia.war /usr/local/tomcat/webapps/

CMD ["catalina.sh", "run"]

Necesitamos construir la imagen de forma que esté accesible desde minikube. Para poder trabajar con el daemon de docker desde el host mac/linux es necesario usar el comando docker-env.

 eval $(minikube docker-env)

Ahora ya podemos usar docker en la línea de comandos hablando con el daemon de docker que se encuentra dentro de la minikube VM.

Construimos la imagen y queda dentro del catálogo de imágenes del Docker que corre dentro de Minikube:

docker build -t cursosautentia .

Creamos el servicio catalogocursos-webapp-svc.yaml:

apiVersion: v1
kind: Service
metadata:
    name: catalogocursos-webapp-service
spec:
    type: NodePort
    selector:
        app: catalogocursos-webapp-service
    ports:
      - name: tomcat
        port: 8080

Creamos el despliegue catalogocursos-webapp-deployment.yaml teniendo en cuenta que en el pod spec debemos poner el mismo nombre de la imagen con el que la construimos (por ejemplo cursosautentia) y establecer «imagePullPolicy» a «Never», para que kubernetes no intente descargar la imagen.

apiVersion: apps/v1 
kind: Deployment
metadata:
  name: catalogocursos-webapp-deployment
spec:
  selector:
    matchLabels:
      app: catalogocursos-webapp-service
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: catalogocursos-webapp-service
    spec:
      containers:
      - image: cursosautentia:latest
        name: cursosautentia
        imagePullPolicy: Never
        ports:
        - containerPort: 8080
          name: cursosautentia

Desplegamos:

kubectl create -f catalogocursos-webapp-svc.yaml

kubectl create -f catalogocursos-webapp-deployment.yaml

Comprobamos que todos los objetos se han creado:

kubectl get all -l app=catalogocursos-webapp-service

NAME                                                    READY     STATUS    RESTARTS   AGE
pod/catalogocursos-webapp-deployment-5f7997cd47-wnpp4   1/1       Running   0          5m

NAME                                                          DESIRED   CURRENT   READY     AGE
replicaset.apps/catalogocursos-webapp-deployment-5f7997cd47   1         1         1         5m

Para ver el log de arranque de la aplicación web y comprobar si todo ha ido bien ejecutamos:

kubectl logs catalogocursos-webapp-deployment-5f7997cd47-wnpp4

Ahora vemos la url que tiene la aplicación para poder acceder a ella desde fuera del clúster con nuestro navegador.

minikube service catalogocursos-webapp-service --url
http://192.168.99.100:32261

Ya podemos acceder a la aplicación desplegada en: http://192.168.99.100:32261/cursosautentia/catalogocursos/cursos?orden=titulo&pagina=1&numElementosPagina=3

Ya con todo funcionando podemos empezar a jugar con Kubernetes todo lo que queramos. Por ejemplo podemos escalar el deployment:

kubectl scale deployments catalogocursos-webapp-deployment --replicas=2

Comprobamos que se nos ha creado un nuevo pod.

kubectl get pods

NAME                                                READY     STATUS    RESTARTS   AGE
catalogocursos-mysql-deployment-ccdb6fdf8-fkd8h     1/1       Running   0          1h
catalogocursos-webapp-deployment-5f7997cd47-wnpp4   1/1       Running   0          53m
catalogocursos-webapp-deployment-5f7997cd47-zxn78   1/1       Running   0          2m

Ahora haciendo diferentes peticiones a la aplicación desplegada, y mirando el log de cada uno de los dos pods de la webapp podemos comprobar como a veces nos responde uno de ellos y en otras ocasiones el otro.

kubectl logs catalogocursos-webapp-deployment-5f7997cd47-wnpp4
kubectl logs catalogocursos-webapp-deployment-5f7997cd47-zxn78

Conclusiones

A lo largo del tutorial hemos visto de una forma muy sencilla cómo podemos desplegar una base de datos en Kubernetes y exponerla como un servicio dentro del clúster. Luego hemos podido desplegar una aplicación web y conectarla a la base de datos, para finalmente acceder a la aplicación desde fuera del clúster con nuestro navegador.

Saludos.

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad