Introducción

En este taller, vamos a ver cómo Kubernetes gestiona el almacenamiento de los contenedores. Para ello, vamos a trabajar con recursos de almacenamiento que se pueden crear en Kubernetes. Estos recursos son PersistentVolume y PersistentVolumeClaim.

Ejercicio 1: Desplegando un servidor web persistente

En este ejercicio, vamos a desplegar un servidor web que guarde los datos en un volumen persistente. Para ello, vamos a crear un PersistentVolume y un PersistentVolumeClaim. El PersistentVolumeClaim se va a asociar al PersistentVolume para que el servidor web pueda acceder a él.

  1. Creamos el fichero que va a definir el PersistentVolume. El fichero es el siguiente:
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvc-serverweb
spec:
    accessModes:
    - ReadWriteOnce
    resources:
      requests:
        storage: 2Gi
  1. Creamos el PersistentVolume con el siguiente comando:
kubectl apply -f pvc-serverweb.yaml

Y comprobamos que se ha creado correctamente:

kubectl get pc, pvc

  1. Creamos el fichero de despliegue del servidor web. El fichero es el siguiente:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-php
  labels:
    app: apache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: apache
  template:
    metadata:
      labels:
        app: apache
    spec:
      volumes:
        - name: volumen-web-php
          persistentVolumeClaim:
            claimName: pvc-webserver
      containers:
        - name: contenedor-apache-php
          image: php:7.4-apache
          ports:
            - name: http-server
              containerPort: 80
          volumeMounts:
            - mountPath: "/var/www/html"
              name: volumen-web-php
  1. Creamos el despliegue con el siguiente comando:
kubectl apply -f web-php.yaml

Y comprobamos que se ha creado correctamente:

kubectl get all

  1. Creamos el fichero de servicio del servidor web. El fichero es el siguiente:
apiVersion: v1
kind: Service
metadata:
  name: servicio-web-php
spec:
  type: NodePort
  ports:
  - name: service-http
    port: 80
    targetPort: http-server
  selector:
    app: apache
  1. Creamos el servicio con el siguiente comando:
kubectl apply -f servicio-web-php.yaml

  1. Creamos el fichero info.php que vamos a guardar en el volumen persistente. Para ello, primero deberemos averiguar la ID del pod:

En la imagen del punto anterior, podemos ver que el pod se llama pod/servidorweb-778bc767f5-dvf7x

Sabido esto, crearemos el fichero info.php con el siguiente comando:

kubectl exec pod/servidorweb-778bc767f5-dvf7x -- bash -c "echo '<?php phpinfo(); ?>' > /var/www/html/info.php"

Para comprobar que se ha creado correctamente, abriremos el fichero php en el navegador:

  1. Como último paso, vamos a comprobar la persistencia, y por ello, vamos a eliminar el despliegue y lo volvemos a crear:
kubectl delete deployment.apps/servidorweb
kubectl apply -f web-php.yaml

Y comprobamos que se ha creado correctamente:

kubectl get all

Y comprobamos que el fichero info.php sigue estando:

Ejercicio 2: Haciendo persistente la aplicación GuestBook

En este ejercicio vamos a desplegar nuestra aplicació Guestbook y vamos a hacer persistente la base de datos.

  1. Creamos el fichero con el que vamos a definir el volumen PersistentVolumenClaim:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: pvc-redis
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 3Gi

Lo aplicamos y comprobamos que se ha creado correctamente:

kubectl apply -f pvc-redis.yaml

  1. Creamos el fichero de despliegue de la base de datos:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: redis
  labels:
    app: redis
    tier: backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: redis
      tier: backend
  template:
    metadata:
      labels:
        app: redis
        tier: backend
    spec:
      volumes:
        - name: volumen-redis
          persistentVolumeClaim:
            claimName: pvc-redis
      containers:
        - name: contenedor-redis
          image: redis
          command: ["redis-server"]
          args: ["--appendonly", "yes"]
          ports:
            - name: redis-server
              containerPort: 6379
          volumeMounts:
            - mountPath: "/data"
              name: volumen-redis
  1. Creamos el despliegue de guestbook:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: guestbook
  labels:
    app: guestbook
    tier: frontend
spec:
  replicas: 3
  selector:
    matchLabels:
      app: guestbook
      tier: frontend
  template:
    metadata:
      labels:
        app: guestbook
        tier: frontend
    spec:
      containers:
      - name: contenedor-guestbook
        image: iesgn/guestbook
        ports:
          - name: http-server
            containerPort: 5000
  1. Creamos el servicio de guestbook:
apiVersion: v1
kind: Service
metadata:
  name: guestbook
  labels:
    app: guestbook
    tier: frontend
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: http-server
  selector:
    app: guestbook
    tier: frontend
  1. Creamos el servicio de redis:
apiVersion: v1
kind: Service
metadata:
  name: redis
  labels:
    app: redis
    tier: backend
spec:
  type: ClusterIP
  ports:
  - port: 6379
    targetPort: redis-server
  selector:
    app: redis
    tier: backend
  1. Realizamos el despliegue de los servicios y comprobamos que se han creado correctamente:
kubectl apply -f .

  1. Comprobamos que la aplicación funciona correctamente:

  1. Eliminamos el despliegue de guestbook y lo volvemos a crear:
kubectl delete -f redis-deployment.yaml
kubectl apply -f redis-deployment.yaml

  1. Accedemos a la aplicación y comprobamos que los datos siguen estando:

Ejercicio 3: Haciendo persistente la aplicación Nextcloud

En este ejercicio vamos a desplegar nuestra aplicación Nextcloud y vamos a hacer persistente tanto la aplicación como la base de datos.

  • Creamos los volúmenes: 1 para la base de datos y otro para la aplicación, ambos de 4GB.
  • Volumen para la base de datos:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: pvc-mariadb
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 4Gi
  • Volumen para la aplicación:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvc-nextcloud
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
        storage: 4Gi

Y los aplicamos:

kubectl apply -f .

  • Creamos el recurso Secret, ejecuta el siguiente comando:
kubectl create cm bd-datos --from-literal=bd_user=nextcloud \
--from-literal=bd_dbname=nextcloud -o yaml --dry-run=client > bd_datos_configmap.yaml

kubectl create secret generic bd-passwords --from-literal=bd_password=nextcloud \
--from-literal=bd_rootpassword=nextcloud -o yaml --dry-run=client > bd_passwords_secret.yaml

Y los desplegamos:

kubectl apply -f bd_datos_configmap.yaml
kubectl apply -f bd_passwords_secret.yaml

  • Creamos el fichero de despliegue de la base de datos.
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mariadb-deployment
  labels:
    app: nextcloud
    type: database
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nextcloud
      type: database
  template:
    metadata:
      labels:
        app: nextcloud
        type: database
    spec:
      containers:
        - name: contenedor-mariadb
          image: mariadb:10.5
          ports:
            - containerPort: 3306
            name: db-port
          env:
            - name: MYSQL_USER
              valueFrom:
                configMapKeyRef:
                  name: bd-datos
                  key: bd_user
            - name: MYSQL_DATABASE
              valueFrom:
                configMapKeyRef:
                  name: bd-datos
                  key: bd_dbname
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: bd-datos
                  key: bd_password
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: bd-datos
                  key: bd_root_password
      volumes:
      - name: volumen-mariadb
        persistentVolumeClaim:
          claimName: pvc-mariadb
  • Creamos el servicio de la base de datos:
apiVersion: v1
kind: Service
metadata:
  name: mariadb-service
  labels:
    app: nextcloud
    type: database
spec:
  selector:
    app: nextcloud
    type: database
  ports:
  - port: 3306
    targetPort: db-port
  type: ClusterIP
  • Creamos el despliegue de Nextcloud:
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nextcloud-deployment
  labels:
    app: nextcloud
    type: frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nextcloud
      type: frontend
  template:
    metadata:
      labels:
        app: nextcloud
        type: frontend
    spec:
      containers:
        - name: contenedor-nextcloud
          image: nextcloud:latest
          ports:
            - containerPort: 80
              name: http-port
            - containerPort: 443
              name: https-port
          env:
            - name: MYSQL_HOST
              value: mariadb-service
            - name: MYSQL_USER
              valueFrom:
                configMapKeyRef:
                  name: bd-datos
                  key: bd_user
            - name: MYSQL_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: bd-datos
                  key: bd_password
            - name: MYSQL_DATABASE
              valueFrom:
                configMapKeyRef:
                  name: bd-datos
                  key: bd_dbname
        volumes:
          - name: volumen-nextcloud
          persistentVolumeClaim:
            claimName: pvc-nextcloud
  • Creamos el servicio de Nextcloud:
apiVersion: v1
kind: Service
metadata:
  name: nextcloud-service
  labels:
    app: nextcloud
    type: frontend
spec:
  selector:
    app: nextcloud
    type: frontend
  ports:
  - name: http-sv-port
    port: 80
    targetPort: http-port
  - name: https-sv-port
    port: 443
    targetPort: https-port
  type: NodePort
  • Creamos el fichero Ingress para Nextcloud:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nextcloud-ingress
  labels:
    app: nextcloud
    type: frontend
spec:
  rules:
  - host: www.maria-nextcloud.org
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nextcloud-service
              port:
                number: http-sv-port
  • Desplegamos los recursos:
kubectl apply -f .

  • Cambiamos el fichero /etc/hosts para que apunte a nuestro cluster:
sudo nano /etc/hosts

  • Accedemos a Nextcloud:

Entramos en el navegador y accedemos a la dirección www.maria-nextcloud.org:

Y nos logueamos con las siguientes credenciales:

  • Usuario: nextcloud
  • Contraseña: bmV4dGNsb3Vk