Taller Kubernetes: Almacenamiento en Kubernetes
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.
- 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
- Creamos el PersistentVolume con el siguiente comando:
kubectl apply -f pvc-serverweb.yaml
Y comprobamos que se ha creado correctamente:
kubectl get pc, pvc

- 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
- Creamos el despliegue con el siguiente comando:
kubectl apply -f web-php.yaml
Y comprobamos que se ha creado correctamente:
kubectl get all

- 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
- Creamos el servicio con el siguiente comando:
kubectl apply -f servicio-web-php.yaml

- 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:

- 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.
- 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

- 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
- 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
- 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
- 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
- Realizamos el despliegue de los servicios y comprobamos que se han creado correctamente:
kubectl apply -f .

- Comprobamos que la aplicación funciona correctamente:

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

- 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
