Despliegue de una aplicación en Kubernetes

Introducción

En este post realizamos la implantación de una aplicación en Docker. En este post vamos a realizar el despliegue de la misma aplicación en Kubernetes.

Ejercicio 1: Despliegue en minikube

En mi casi caso, voy a elegir bookmedik como aplicación a desplegar. Para ello, voy a utilizar el siguiente repositorio que contiene el código de la aplicación.

Despliegue de la aplicación

  • Creamos los ficheros yaml para crear un ConfigMap y un Secret donde guardaremos las variables de entorno.
    kubectl create cm cm-mariadb --from-literal=mysql_usuario=bookmedik \
    --from-literal=basededatos=bookmedik \
    -o yaml --dry-run=client > bd_datos_configmap.yaml

    kubectl create secret generic secret-mariadb --from-literal=password=bookmedik \
    --from-literal=rootpass=root \
    -o yaml --dry-run=client > bd_passwords_secret.yaml
    

1

Creamos el volumen y el fichero de despliegue para mariadb

  • Volumen para mariadb
        apiVersion: v1
        kind: PersistentVolumeClaim
        metadata:
            name: mariadb-pvc
        spec:
            accessModes:
            - ReadWriteOnce
            resources:
            requests:
                storage: 3Gi
        
  • Despliegue de mariadb
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: mariadb
        labels:
          app: mariadb
          tier: backend
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: mariadb
            tier: backend
        template:
          metadata:
            labels:
              app: mariadb
              tier: backend
          spec:
            volumes:
              - name: volumen-mariadb
                persistentVolumeClaim:
                  claimName: mariadb-pvc
            containers:
              - name: contenedor-mariadb
                image: mariadb:10.5
                env:
                  - name: MARIADB_ROOT_PASSWORD
                    valueFrom:
                      secretKeyRef:
                        name: secret-mariadb
                        key: rootpass
                  - name: MARIADB_DATABASE
                    valueFrom:
                      configMapKeyRef:
                        name: cm-mariadb
                        key: basededatos
                  - name: MARIADB_USER
                    valueFrom:
                      configMapKeyRef:
                        name: cm-mariadb
                        key: mysql_usuario
                  - name: MARIADB_PASSWORD
                    valueFrom:
                      secretKeyRef:
                        name: secret-mariadb
                        key: password
                ports:
                  - name: mariadb-server
                    containerPort: 3306
                volumeMounts:
                  - mountPath: "/var/lib/mysql"
                    name: volumen-mariadb
        
  • Servicio de mariadb
        apiVersion: v1
        kind: Service
        metadata:
          name: mariadb
          labels:
            app: mariadb
            tier: backend
        spec:
          type: ClusterIP
          ports:
            - port: 3306
              targetPort: mariadb-server
          selector:
            app: mariadb
            tier: backend
        

Creamos los ficheros de despliegue y servicios para bookmedik.

  • Despliegue de bookmedik
        apiVersion: apps/v1
        kind: Deployment
        metadata:
          name: bookmedik
          labels:
            app: bookmedik
            tier: frontend
        spec:
          replicas: 2
          selector:
            matchLabels:
              app: bookmedik
              tier: frontend
          template:
            metadata:
              labels:
                app: bookmedik
                tier: frontend
        spec:
          containers:
          - name: contenedor-bookmedik
            image: legnakra/bookmedik:latest
            env:
              - name: USUARIO_BOOKMEDIK
                valueFrom:
                  configMapKeyRef:
                    name: cm-mariadb
                    key: mysql_user
              - name: PASS_BOOKMEDIK
                valueFrom:
                  secretKeyRef:
                    name: secret-mariadb
                    key: mysql_password
              - name: BASE_DATOS_BOOKMEDIK
                valueFrom:
                  configMapKeyRef:
                    name: cm-mariadb
                    key: mysql_database
            ports:
              - name: http-server
                containerPort: 80
        
  • Servicio de bookmedik
        apiVersion: v1
        kind: Service
        metadata:
          name: bookmedik
          labels:
            app: bookmedik
            tier: frontend
        spec:
          type: NodePort
          ports:
            - port: 80
              targetPort: http-server
          selector:
            app: bookmedik
            tier: frontend
        

Creamos todo y anotamos la primera versión de la aplicación.

    kubectl apply -f .
    

Comprobamos que los recursos se han creado correctamente.

2

    kubectl annotate deployment.apps/bookmedik kubernetes.io/change-cause="Versión 1"
    

3

  • Accedemos a la aplicación y comprobamos que funciona correctamente.

4

Y comprobamos que podemos acceder:

5

Creamos el fichero Ingress para acceder a la aplicación desde el exterior.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: bookmedik-ingress
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
    spec:nano
      rules:
      - host: www.maria-bookmedik.org
        http:
          paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: bookmedik
                port:
                  number: 80
    

Y lo creamos:

    kubectl apply -f bookmedik-ingress.yaml
    

6

  • Modificamos el fichero /etc/hosts para que apunte a la IP del nodo maestro.

7

  • Accedemos a la aplicación desde el navegador.

8

Y accedemos a la zona de administración:

9

  • Creamos información para probar la persistencia de la base de datos cuando borremos la base de datos de mariadb.

10

  • Eliminamos el despliegue de mariadb.
      kubectl delete deployment.apps/mariadb
      

11

  • Comprobamos que la base de datos no funciona.

12

  • Ahora nos toca escalar el despliegue de la aplicación a 3 réplicas y lo podemos hacer de dos formas:

    • Modificando el fichero de despliegue y aplicando los cambios, haciéndolo persistente.

    • Modificando el despliegue en caliente, es decir, sin hacer persistente el cambio, ejecutando kubectl scale <deploy-name> --replicas=<num_replicas>.

En mi caso, quiero hacerlo de forma no persistente, por lo que ejecuto el comando:

  kubectl scale deployment.apps/bookmedik --replicas=3
  

Y comprobamos que se ha escalado correctamente.

13

  • Vamos a crear una imagen docker, pero con alguna modficación, para probar el despliegue de una nueva versión de la aplicación.

  • Modificamos el fichero index.php de la aplicación para que muestre la versión de la aplicación.

14

En mi caso, le he cambiado el texto de la página principal y de la pestaña del navegador.

  • Creamos la imagen docker con la nueva versión de la aplicación.
    docker build -t legnakra/bookmedik:v1_1 .
    

15

  • Subimos la imagen a docker hub.
    docker push legnakra/bookmedik:v1_1
    

16

  • Modificamos el fichero de despliegue para que use la nueva versión de la imagen.

17

  • Aplicamos los cambios.
    kubectl apply -f bookmedik-deployment.yaml
    

18

18.1

  • Comprobamos que se ha desplegado la nueva versión de la aplicación.

19

Y que podemos acceder a la zona de administración.

20

Ejercicio 2: Despliegue en otra distribución de kubernetes

En esta parte, vamos a instalar un cluster de kubernetes. Pero lo haremos en una distribución diferente a la que hemos usado hasta ahora. Pero debemos hacerlo en otra versión, y he decidido hacerlo en k3s, que es una versión ligera de kubernetes.

  • Creamos 3 nodos, uno maestro y dos esclavos.
    # -*- mode: ruby -*-
    # vi: set ft=ruby :

    Vagrant.configure("2") do |config|
      config.vm.define :controller do |controller|
        controller.vm.box = "debian/buster64"
        controller.vm.hostname = "controller"
        controller.vm.network :private_network, ip: "192.168.0.10"
        controller.nfs.verify_installed = false
        controller.vm.synced_folder '.', '/vagrant', disabled: true
        controller.vm.provider "libvirt" do |v|
          v.memory = 3072
          v.cpus = 2
        end
      end
      config.vm.define :worker1 do |worker1|
        worker1.vm.box = "debian/buster64"
        worker1.vm.hostname = "worker1"
        worker1.vm.network :private_network, ip: "192.168.0.20"
        worker1.nfs.verify_installed = false
        worker1.vm.synced_folder '.', '/vagrant', disabled: true
        worker1.vm.provider "libvirt" do |v|
          v.memory = 3072
          v.cpus = 2
        end
      end
      config.vm.define :worker2 do |worker2|
        worker2.vm.box = "debian/buster64"
        worker2.vm.hostname = "worker2"
        worker2.vm.network :private_network, ip: "192.168.0.30"
        worker2.nfs.verify_installed = false
        worker2.vm.synced_folder '.', '/vagrant', disabled: true
        worker2.vm.provider "libvirt" do |v|
          v.memory = 3072
          v.cpus = 2
        end
      end
    end
    
  • Instalamos k3s en el nodo maestro.
    curl -sfL https://get.k3s.io | sh -
    

21

Y comprobamos que está listo.

    kubectl get nodes
    

22

  • Identificamos el token del nodo maestro.
    sudo cat /var/lib/rancher/k3s/server/node-token
    K100ce50339c5ff211169afea38d299cc60ea62c65b98d102b49df1e1c535b8da7f::server:611c1ed3c8c978a4048e541fac5e1061
    
  • Ejecutamos lo siguiente:
    curl -sfL https://get.k3s.io | K3S_URL=https://192.168.121.241:6443 K3S_TOKEN=K100ce50339c5ff211169afea38d299cc60ea62c65b98d102b49df1e1c535b8da7f::server:611c1ed3c8c978a4048e541fac5e1061 sh -
    

23

24

El comando anterior nos instala k3s en el nodo esclavo y lo añade al cluster. En el parámetro URL, debemos poner la IP del nodo maestro y en el parámetro token, el token que hemos obtenido en el paso anterior.

  • Comprobamos que los nodos están listos.
    kubectl get nodes
    
![25](/images/kubernetes/p1/25.png)
  • Instalamos git en el nodo maestro ( controller).
    apt install git
    
  • Clonamos el repositorio de la aplicación.
    git clone https://github.com/Legnakra/Kubernetes-bookmedik.git
    
  • Rehacemos los pasos que hicimos en el ejercicio anterior:

    • Creamos los ficheros yaml para crear un ConfigMap y un Secret donde guardaremos las variables de entorno.
      kubectl create cm cm-mariadb --from-literal=mysql_usuario=bookmedik --from-literal=basededatos=bookmedik

      kubectl create secret generic secret-mariadb --from-literal=password=bookmedik --from-literal=rootpass=root 
      

26

  • Creamos los recursos:
      kubectl apply -f pvc-bookmedik.yaml
      kubectl apply -f mariadb-deployment.yaml
      kubectl apply -f mariadb-service.yaml
      kubectl apply -f bookmedik-deployment.yaml  
      kubectl apply -f bookmedik-service.yaml
      kubectl apply -f bookmedik-ingress.yaml  
      

27

  • Comprobamos que todo está listo.
      kubectl get all
      

28

29

  • Accedemos a la dirección que hemos establecido en el fichero ‘bookmedik-ingress.yaml’.

30

Y que podemos acceder a la zona de administración.

31

  • Escalamos el despliegue como hemos hecho en el ejercicio anterior, y lo realizaremos con 3 replicas. Para ello, primero, veamos de nuevo que contamos con 2 replicas y vamos a extenderlo a 1 más.

  • Antes de escalar el despliegue, vamos a ver las replicas que tenemos.

    kubectl get pods -o wide
    

32

  • Ahora, vamos a escalar el despliegue.
    kubectl scale deployment.apps/bookmedik --replicas=3
    
  • Comprobamos que se ha escalado correctamente y que tenemos 3 replicas.
    kubectl get pods -o wide
    

33

  • Comprobamos que podemos acceder a la aplicación.

34

Y que podemos acceder a la zona de administración.

35