Volumes

Volumenes

Los volúmenes son puntos de montaje que se utilizan para compartir datos entre contenedores o almacenaje persistente de datos.

Tipos de Volúmenes

emptydir: es un directorio vacio que se crea como volumen y va ligado a la vida del pod, mientras el pod viva ese volumen seguirá existiendo y manteniendo los datos, los containers dentro del pod pueden morir y revivir las veces que quieran que el volumen seguirá existiendo, pero si muere el pod el volumen desaparece.

hostPath: es un directorio que en forma de volumen y va ligado a la vida del nodo, ese directorio existirá en el nodo, si un pod muere y se despliega en otro nodo no podrá acceder a la información del volumen donde murió, este volumen existirá hasta que se elimine o el nodo muera.

Volumenes cloud: kubernetes permite crear puntos de montaje en diferentes plataformas como aws, openstack, google cloud, donde previamente a de haber una configuración en el nodo para conectar con la plataforma.

PV/PvC: mas que un tipo de montaje es una metodología que utiliza kubernetes para separar el trabajo del desarrollador al de administrador.

Funciona de la siguiente manera, un pod solicita el punto de montaje al objeto PvC (Persistent Volume claim) en este objeto se especifica la capacidad que se quiere, el PvC pide ese espacio al objeto PV (Persistent volume) que este sabe donde esta cada disco externo al nodo y su capacidad, si lo solicitado por el PvC esta disponible en algún PV el punto de montaje se crea.

De esta manera los desarrolladores no tienen que preocuparse d donde almacenar los datos, solo solicitan el espacio deseado, y los administradores ponen espacio disponible a disposición de recogida.

Diferentes tipos de funcionamientos:

  • retain: en caso de eliminar el pvc, retener el pv y los datos de disco, ademas no podrá ser usado por otro pvc

  • recycle: en caso de eliminar el pvc el pv se mantiene pero los datos del disco se borran para que otro pvc lo reclame.

  • delete: en este caso si eliminas el pvc también eliminas el pv y los datos del disco.

Emptydir

Este tipo de montaje al ser muy volátil es utilizado normalmente para guardar cache o archivos que pueden perderse. Una vez muera el POD los datos del punto de montaje se perderán.

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: nginx:alpine
    name: test-container
    volumeMounts:
    - mountPath: /cache
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

Ruta del directorio local

/var/lib/kubelet/pods/b60897a7-f689-4bff-bef6-0545d1727f9b/volumes/kubernetes.io~empty-dir/cache-volume

HostPath

hostPath es un punto de montaje a nivel de nodo, en el nodo persistirán los datos pero si el pod por la razón que sea cambia de nodo, no podrá llegar a los datos a del anterior nodo.

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: nginx.alpine
    name: test-container
    volumeMounts:
    - mountPath: /usr/share/nginx/html
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # directory location on host
      path: /data/front-nginx

Volumen AWS ebs

Este es un ejemplo de punto de montaje con un volumen creado en amazon ebs, se indica el id del volumen a montar. La ventaja de estos puntos de montaje, son que los datos están disponibles en todos los nodos y no hay perdidas ni conflictos, la desventaja que se utiliza una entidad externa.

apiVersion: v1
kind: Pod
metadata:
  name: test-ebs
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-ebs
      name: test-volume
  volumes:
  - name: test-volume
    # This AWS EBS volume must already exist.
    awsElasticBlockStore:
      volumeID: vol-0fb30c332ecff512d
      fsType: ext4

Nota: Este proceso de montaje requiere una configuración previa, tanto de amazon ebs con usuarios especiales IAM, como de cada nodo establecer la conexión con amazon correctamente con aws-clie

PV/PvC

Esta metodología qu a creado kubernetes, en un principio se hace pesada de utilizar y un tanto engorrosa, pero una vez te acostumbras, acaba siendo muy útil y rápida de utilizar, sobre todo en su opción dinámica.

PV y PvC son dos objetos diferentes donde PvC solicita un espacio determinado y PV lo proporciona si esta disponible.

En el siguiente ejemplo se ve un PV con 5Gi de espacio disponible, permisos sobre el espacio de ReadWriteOnce escritura y lectura solo por un PvC y que ese espacio está en /mnt/data

El PvC que se observa solicita a cualquier PV que exista: 5Gi de espacio readWriteOnce y que en ese espacio solo pueda escribir el.

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

Una vez desplegado se observa que el PvC se a asignado al PV que había.

➜ sudo kubectl get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
pv-volume   5Gi        RWO            Retain           Bound    default/pv-claim   manual

➜ sudo kubectl get pvc
NAME       STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pv-claim   Bound    pv-volume   5Gi        RWO            manual         18s

Selectors

Los selectores es una manera de especificar a que PV quieres que se asigne un PvC. En el siguiente ejemplo se muestra un PvC que se asigna a un PV que tenga el label type:local.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  selector:
    matchLabels:
      type: local

Se puede observar que teniendo dos PV disponibles se a asociado al que coincide con el label indicado.

NAME              CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM              STORAGECLASS   REASON   AGE
pv-volume         5Gi        RWO            Retain           Bound       default/pv-claim
pv-volume-mysql   5Gi        RWO            Retain           Available                  

Asignar pvc a pod

Teniendo el siguiente PvC corriendo, asigno un POD a este para mostrar un ejemplo de funcionamiento.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-claim
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi
  selector:
    matchLabels:
      mysql: local

Para asociar un PvC a un POD solo se tiene que indicar el nombre del PvC en la sección volumes con la opción persistentVolimeClaim y claimName

apiVersion: apps/v1
kind: Deployment
metadata:
  name: deploy-mysql
  labels:
    app: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:latest
        env:
          - name: MYSQL_ROOT_PASSWORD
            value: "12345678"
        volumeMounts:
        - mountPath: "/var/lib/mysql"
          name: vol-mysql
      volumes:
        - name: vol-mysql
          persistentVolumeClaim:
            claimName: pv-claim

Resultado del montaje:

# se a creado el POD del deployment
➜ sudo kubectl get pods
NAME                            READY   STATUS    RESTARTS   AGE
deploy-mysql-6c5cdb988b-7w9cp   1/1     Running   0          26s

# el pvc pc-claim se a asociado al PV pv-volume
➜ sudo kubectl get pvc 
NAME       STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS   AGE
pv-claim   Bound    pv-volume   5Gi        RWO            manual         35s

➜ sudo kubectl get pv 
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM              STORAGECLASS   REASON   AGE
pv-volume   5Gi        RWO            Retain           Bound    default/pv-claim   manual

# Y desde el host podemos ver el directorio que se a montado 
➜ ls /mnt/data 
 auto.cnf        binlog.000002   ca-key.pem   client-cert.pem   ib_buffer_pool ...  

StorageClass dinamico

Esta es una opción para facilitar rápidamente a los desarrolladores puntos de montaje, con esta opción solo tienes que crear un PvC y StorageClass te crea un PV con unos valores por defecto.

Por defecto minikube ya tiene creado un storageclass como HostPath, por lo contrario con minikube no puede configurar un StorageClass dinamico para la nube.

# sc abreviación de storageClass
➜ sudo kubectl get sc
NAME                 PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
standard (default)   k8s.io/minikube-hostpath   Delete          Immediate           false

Solo creando un PvC storageClass ya nos proporciona el punto de montaje.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: sc-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 5Gi

Comprobación de que se a creado el pv automáticamente:

Atención: el PV lo crea en modo delete si borras el PvC se borraran tanto los datos como el PV, esto solo es un entorno de pruebas, se puede cambiar utilizando sudo kubectl edit storageClass standard

# despliego el PvC
➜ sudo kubectl apply -f volumenes/storage-class.yml 
persistentvolumeclaim/sc-pvc created

# ompruevo que se a asignado a un PV
➜ sudo kubectl get pvc
NAME     STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
sc-pvc   Bound    pvc-a1ac3b34-d19c-4bd8-8fd5-26cc4ae1123b   5Gi        RWO            standard       16s

➜ sudo kubectl get pv 
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM            STORAGECLASS   REASON   AGE
pvc-a1ac3b34-d19c-4bd8-8fd5-26cc4ae1123b   5Gi        RWO            Delete           Bound    default/sc-pvc   standard                24s

# Observo que el pv crea un punto de montaje en tmp.
➜ sudo kubectl describe pv pvc-a1ac3b34-d19c-4bd8-8fd5-26cc4ae1123b
Name:            pvc-a1ac3b34-d19c-4bd8-8fd5-26cc4ae1123b
StorageClass:    standard
Status:          Bound
Claim:           default/sc-pvc
Reclaim Policy:  Delete
Access Modes:    RWO
VolumeMode:      Filesystem
Capacity:        5Gi
Message:         
Source:
    Type:          HostPath (bare host directory volume)
    Path:          /tmp/hostpath-provisioner/pvc-a1ac3b34-d19c-4bd8-8fd5-26cc4ae1123b

NFS

nfs junto con kubernetes es una manera de tener puntos de montaje en el cluster sin utilizar una plataforma externa.

El funcionamiento de esto es Montar un servidor NFS en el que todos los nodos del cluster tengan acceso y desde los nodos utilizar PV/PvC.

apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
  labels:
    datos: nfs
spec:
  storageClassName: manual
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteMany
  nfs:
    server: my-nfs-server
    path: "/var/shared"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: manual
  resources:
    requests:
      storage: 5Gi
  selector:
    matchLabels:
      datos: nfs

Dinámico

El aprovisionamiento dinámico es un recurso normalmente en la nube, donde se crean volumenes automáticamente al solicitarlos.

Los puntos de aprovisionamiento dinámico están diseñados para dar puntos de montaje rápidamente y sin tener que pedir permiso al administrador. Hasta ahora el diseñador cada vez que quería pedir un punto de montaje con un PVC, el administrador tenia que crear un PV manualmente, con el aprovisionamiento dinámico esto se automatiza.

Nfs

https://github.com/kubernetes-incubator/external-storage/tree/master/nfs-client/deploy

Por defecto kubernetes deja esta metodología para terceros y proporciona el siguiente git para configurar un servidor nfs como aprovisionamiento dinámico.

Previamente se tiene que disponer de un servidor nfs configurado

Los archivos del repositorio proporcionan un deployment para poder gestionar las solicitudes de storage en el namespace en el que se despliege, ademas un archivo rbac.yaml con todos los permisos necesarios para hacer posible esta gestión.

Configuración del nfs server
pi@raspberrypi:~ $ cat /etc/exports 
/srv/dinamic        192.168.88.0/24(rw,sync,no_subtree_check,no_root_squash,no_all_squash,insecure)

pi@raspberrypi:~ $ ls -l /srv/
total 20
drwxr-xr-x  2 nobody   root             4096 May  6 19:14 dinamic
Despliegue requerido

Despliegue de los archivos requeridos para el funcionamiento de nfs dinámico proporcionados por el git de esta sección.

➜ kubectl apply -f rbac.yaml 
serviceaccount/nfs-client-provisioner created
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner created
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner created
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner created

➜ kubectl get clusterrole,role,rolebinding,clusterrolebinding,svc | grep nfs
clusterrole.rbac.authorization.k8s.io/nfs-client-provisioner-runner                                          10m
role.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner   10m
rolebinding.rbac.authorization.k8s.io/leader-locking-nfs-client-provisioner   10m
clusterrolebinding.rbac.authorization.k8s.io/run-nfs-client-provisioner                             10m

➜ kubectl apply -f deployment.yaml 
deployment.apps/nfs-client-provisioner created
StorageClass

StorageClass es el objeto que kubernetes proporciona para el almacenamiento dinámico

class.yml

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: my-nfs-provisioner # or choose another name, must match deployment's env PROVISIONER_NAME'
parameters:
  archiveOnDelete: "false"
reclaimPolicy: Delete # Delete | Retain | recycle

Aplicar StorageClass y visualizar

➜ kubectl apply -f class.yaml                                               
storageclass.storage.k8s.io/managed-nfs-storage created

➜ kubectl get storageclass,deploy
NAME                                              PROVISIONER                RECLAIMPOLICY   VOLUMEBINDINGMODE   ALLOWVOLUMEEXPANSION   AGE
storageclass.storage.k8s.io/managed-nfs-storage   my-nfs-provisioner         Delete          Immediate           false                  57s
storageclass.storage.k8s.io/standard (default)    k8s.io/minikube-hostpath   Delete          Immediate           false                  81d

NAME                                     READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nfs-client-provisioner   1/1     1            1           49s
Comprobar

Para comprobar creamos un PVC y automáticamente se tiene que crear un PV asociado y un directorio en el servidor nfs.

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: test-claim
  annotations:
    volume.beta.kubernetes.io/storage-class: "managed-nfs-storage"
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 10Mi

Despliegue:

# no hay pv, pvc exisentes
➜ kubectl get pv,pvc                                          
No resources found in default namespace.

# crear PVC
➜ kubectl apply -f test-claim.yml

# automaticamente se a creado un PV asociado al PVC
➜ kubectl get pv,pvc              
NAME                                                        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS          REASON   AGE
persistentvolume/pvc-1355ca1f-7e3a-4b67-a0aa-b9bdc229baae   10Mi       RWX            Delete           Bound    default/test-claim   managed-nfs-storage            5s

NAME                               STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS          AGE
persistentvolumeclaim/test-claim   Bound    pvc-1355ca1f-7e3a-4b67-a0aa-b9bdc229baae   10Mi       RWX            managed-nfs-storage   5s

# En el servidor nfs se a creado el recurso automaticamente
pi@raspberrypi:~ $ ls -l /srv/dinamic/
total 4
drwxrwxrwx 2 root root 4096 May  6 19:12 default-test-claim-pvc-1355ca1f-7e3a-4b67-a0aa-b9bdc229baae