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