1 - Volumes

Los archivos localizados dentro de un contenedor son efímeros, lo cual presenta problemas para aplicaciones no triviales cuando se ejecutan en contenedores. Un problema es la pérdida de archivos cuando el contenedor termina. Kubelet reinicia el contenedor con un estado limpio. Un segundo problema ocurre cuando compartimos ficheros entre contenedores corriendo juntos dentro de un Pod. La abstracción volume de Kubernetes resuelve ambos problemas. Se sugiere familiaridad con Pods

Trasfondo

Docker tiene el concepto de volúmenes, aunque es algo más flojo y menos controlado. Un volumen de Docker es un directorio en disco o en otro contenedor. Docker provee controladores de volúmenes, pero la funcionalidad es algo limitada.

Kubernetes soporta muchos tipos de volúmenes. Un Pod puede utilizar cualquier número de tipos de volúmenes simultáneamente. Los tipos de volúmenes efímeros tienen el mismo tiempo de vida que un Pod, pero los volúmenes persistentes existen más allá del tiempo de vida de un Pod. Cuando un Pod deja de existir, Kubernetes destruye los volúmenes efímeros; sin embargo, Kubernetes no destruye los volúmenes persistentes. Para cualquier tipo de volumen en un Pod dado, los datos son preservados a lo largo de los reinicios del contenedor.

En su núcleo, un volumen es un directorio, posiblemente con algunos datos en este, que puede ser accesible para los contenedores en un Pod. Cómo ese directorio llega a crearse, el medio que lo respalda, y el contenido de este se determinan por el tipo de volumen usado.

Para usar un volumen, especifica los volúmenes a proveer al por en .spec.volumes y declara dónde montar estos volúmenes dentro de los contenedores en .spec.containers[*].volumeMounts. Un proceso en el contenedor observa una vista del sistema de archivos compuesta por la imagen Docker y volúmenes. La imagen Docker está en la raíz de la jerarquía del sistema de archivos. Los volúmenes se montan en las rutas especificadas dentro de la imagen. Los volúmenes no se pueden montar en otros volúmenes o tener enlaces duros a otros volúmenes. Cada contenedor en la configuración del Pod debe especificar de forma independiente donde montar cada volumen.

Tipos de volúmenes

Kubernetes soporta varios tipos de volúmenes

awsElasticBlockStore

Un volumen awsElasticBlockStore monta un volumen EBS de Amazon Web Services (AWS) en tu Pod. A diferencia de emptyDir, que se borra cuando se quita un Pod, el contenido de un volumen EBS es persistido cuando se desmonta el volumen. Esto significa que un volumen EBS puede ser pre-poblado con datos, y que los datos puedes ser compartidos entre pods.

Existen algunas restricciones cuando usas un volumen awsElasticBlockStore:

  • Los nodos en los que corren los pods deben ser instances AWS EC2.
  • Estas instancias deben estar en la misma región y zona de disponibilidad que el volumen EBS
  • EBS solo soporta una única instancia EC2 montando un volumen

Creando un volumen AWS EBS

Antes poder usar un volumen EBS en un Pod, necesitas crearlo.

aws ec2 create-volume --availability-zone=eu-west-1a --size=10 --volume-type=gp2

Asegúrate de que la zona coincide con la zona en que has creado el clúster. Revisa que el tamaño y el tipo de volumen EBS son compatibles para tu uso.

Ejemplo de configuración AWS EBS

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
      # Este volumen EBS debe existir anteriormente.
      awsElasticBlockStore:
        volumeID: "<volume id>"
        fsType: ext4

Si el volumen EBS está particionado, puedes suministrar el campo opcional partition: "<partition number>" para especificar cuál partición montar.

Migración CSI AWS EBS CSI

FEATURE STATE: Kubernetes v1.17 [beta]

La función CSIMigration para awsElasticBlockStore, cuando se habilita, redirige todas las operaciones de complemento desde el complemento existente dentro del árbol existente al controlador de Interfaz de Almacenamiento del Contenedor (CSI) de ebs.csi.aws.com. Para utilizar esta función, el controlador AWS EBS CSI debe ser instalado en el clúster y las características beta CSIMigration y CSIMigrationAWS deben estar habilitadas.

Migración CSI AWS EBS CSI completa

FEATURE STATE: Kubernetes v1.17 [alpha]

Para desactivar el complemento de almacenamiento awsElasticBlockStore de ser cargado por el administrador de controladores y el kubelet, establece el atributo CSIMigrationAWSComplete a true. Esta función requiere tener instalado el controlador de interfaz de almacenamiento del contenedor (CSI) en todos los nodos en obreros.

azureDisk

El tipo de volumen azureDisk monta un Data Disk de Microsoft Azure en el Pod.

Para más detalles, mira el azureDisk volume plugin.

Migración CSI azureDisk

FEATURE STATE: Kubernetes v1.19 [beta]

La función CSIMigration para azureDisk, cuando se habilita, redirige todas las operaciones de complemento desde el complemento existente dentro del árbol existente al controlador de Interfaz de Almacenamiento del Contenedor (CSI) de disk.csi.azure.com. Para utilizar esta función, el controlador Azure Disk CSI debe ser instalado en el clúster y las características beta CSIMigration y CSIMigrationAzureDisk deben estar habilitadas.

azureFile

El tipo de volumen azureFile monta un volumen de ficheros de Microsoft Azure (SMB 2.1 and 3.0) en un Pod.

Para más detalles, mira el azureFile volume plugin.

Migración CSI azureFile CSI

FEATURE STATE: Kubernetes v1.21 [beta]

La función CSIMigration para azureFile, cuando se habilita, redirige todas las operaciones de complemento desde el complemento existente dentro del árbol existente al controlador de Interfaz de Almacenamiento del Contenedor (CSI) de file.csi.azure.com. Para utilizar esta función, el controlador Azure File CSI Driver debe ser instalado en el clúster y las feature gates CSIMigration y CSIMigrationAzureFile deben estar habilitadas.

El controlador Azure File CSI no soporta usar el mismo volumen con fsgroups diferentes, si está habilitadla migración CSI Azurefile, usar el mismo volumen con fsgorups diferentes no será compatible en absoluto.

cephfs

Un volumen cephfs permite montar un volumen CephFS existente en tu Pod. A diferencia de emptydir, que es borrado cuando se remueve el Pod, el contenido de un volumen cephfs es preservado y el volumen es meramente desmontado. Esto significa que un volumen cephfspuede ser pre-poblado por múltiples escritores simultáneamente.

Mira el CephFS example para más detalles.

cinder

El tipo de volumen cinder se usa para montar un volumen Cinder de OpenStack en tu Pod.

Cinder volume configuration example

apiVersion: v1
kind: Pod
metadata:
  name: test-cinder
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: test-cinder-container
      volumeMounts:
        - mountPath: /test-cinder
          name: test-volume
  volumes:
    - name: test-volume
      # Este volumen de  OpenStack debe existir anteriormente.
      cinder:
        volumeID: "<volume id>"
        fsType: ext4

Migración CSI OpenStack

FEATURE STATE: Kubernetes v1.21 [beta]

La función CSIMigration para Cinder está habilitada por defecto en Kubernetes 1.21. Esta redirige todas las operaciones de complemento desde el complemento existente dentro del árbol existente al controlador de Interfaz de Almacenamiento del Contenedor (CSI) de cinder.csi.openstack.org. El controlador OpenStack Cinder CSI Driver debe estar instalado en el clúster.

Puedes deshabilitar la migración CSI para tu clúster estableciendo el feature gate CSIMigrationOpenStack a false. Si deshabilitas la función CSIMigrationOpenStack, el complemento del volumen Cinder dentro del árbol toma la responsabilidad para todos los aspectos de la administración del almacenamiento del volumen Cinder.

configMap

Un ConfigMap provee una manera de inyectar datos de configuración a los pods. Los datos almacenados en un ConfigMap se pueden referenciar en un volumen de tipo configMap y luego ser consumidos por aplicaciones contenerizadas corriendo en un Pod.

Cuando haces referencia a un ConfigMap, provees el nombre del ConfigMap en el volumen. Puedes personalizar la ruta para una entrada específica en el ConfigMap. La siguiente configuración muestra cómo montar un ConfigMap log-config en un Pod llamado configmap-pod:

apiVersion: v1
kind: Pod
metadata:
  name: configmap-pod
spec:
  containers:
    - name: test
      image: busybox
      volumeMounts:
        - name: config-vol
          mountPath: /etc/config
  volumes:
    - name: config-vol
      configMap:
        name: log-config
        items:
          - key: log_level
            path: log_level

El ConfigMap log-config es montado como un volumen, y todo el contenido almacenado en su entrada log_level es montado en el Pod en la ruta /etc/config/log_level. Ten en cuenta que esta ruta se deriva del mountPathdel volumen y el path cuya clave es log_level.

downwardAPI

Un volumen de downwardAPI hace que los datos API descendentes estén disponibles para las aplicaciones. Monta un directorio y escribe los datos solicitados en archivos de texto sin formato.

Mira el downward API example para mayores detalles.

emptyDir

Un volumen emptyDires creado primero cuando se asigna un Pod a un nodo, y existe mientras el Pod está corriendo en el nodo. Como su nombre lo indica un volumen emptydirestá inicialmente vacío. Todos los contenedores en el Pod pueden leer y escribir los archivos en el volumen emptyDir, aunque ese volumen se puede montar en la misma o diferente ruta en cada contenedor. Cuando un Pod es removido del nodo por alguna razón, los datos en emptydir se borran permanentemente.

Algunos usos para un emptyDir son:

  • Espacio temporal, como para una clasificación de combinación basada en disco
  • Marcar un largo cálculo para la recuperación de fallos
  • Contener archivos que un contenedor de administrador de contenido recupera mientras un contenedor de servidor web sirve los datos

Dependiendo de tu entorno, los volúmenes emptydir se almacenan en cualquier medio que respalde el nodo tales como disco SSD, o almacenamiento de red. Sin embargo, si se establece el campo emptydir.medium a Memory, Kubernetes monta en su lugar un tmpfs (sistema de ficheros respaldado por la RAM). Mientras que tmpfs es muy rápido, ten en cuenta que a diferencia de los discos, tmpfs se limpia cuando el nodo reinicia y cualquier archivo que escribas cuenta con el límite de memoria del contenedor.

Ejemplo de configuración de emptyDir

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: test-container
      volumeMounts:
        - mountPath: /cache
          name: cache-volume
  volumes:
    - name: cache-volume
      emptyDir: {}

fc (canal de fibra)

Un tipo de volumen fc permite que un volumen de almacenamiento de bloque de canal de fibra existente se monte en un Pod. Puede especificar nombres mundiales de destino únicos o múltiples (WWN) utilizando el parámetro targetWWNs en su configuración de volumen. Si se especifican varios WWN, targettWWNs esperan que esos WWN sean de conexiones de múltiples rutas.

Revisa el ejemplo de canal de fibra para más detalles.

flocker (deprecado)

Flocker es un administrador open-source de volúmenes de contenedor agrupado por clúster. Flocker proporciona administración y orquestación de volúmenes de datos respaldados por una variedad de backends de almacenamiento.

Un volumen flocker permite montar un conjunto de datos Flocker en un Pod. Si el conjunto de datos no existe en Flocker, necesita ser creado primero con el CLI de Flocker o usando la API de Flocker. Si el conjunto de datos existe será adjuntado de nuevo por Flocker al nodo donde el Pod está programado. Esto significa que los datos pueden ser compartidos entre pods como sea necesario.

Mira el ejemplo de Flocker para más detalles.

gcePersistentDisk

Un volumen gcePersistentDisk monta un volumen de Google Compute Engine (GCE) de disco persistente (DP) en tu Pod. A diferencia de emptyDir, que se borra cuando el Pod es removido, el contenido de un disco persistente es preservado y el volumen solamente se desmonta. Esto significa que un disco persistente puede ser pre-poblado con datos, y que esos datos se pueden compartir entre pods.

Existen algunas restricciones cuando usas gcePersistentDisk:

  • Los nodos en los que se ejecutan los pods deben ser máquinas virtuales GCE.
  • Esas máquinas virtuales deben estar en el mismo proyecto GCE y zona que el disco persistente se encuentra.

Una de las características del disco persistente CGE es acceso concurrente de solo lectura al disco persistente. Un volumen gcePersistentDisk permite montar simultáneamente un disco de solo lectura a múltiples consumidores. Esto significa que puedes pre-poblar un DP con tu conjunto de datos y luego servirlo en paralelo desde tantos pods como necesites. Desafortunadamente, los DPs solo se pueden montar por un único consumidor en modo lectura-escritura. No están permitidos escritores simultáneos.

Usar un disco persistente GCE con un Pod controlado por un ReplicaSet fallará a manos que el DP sea de solo lectura o el número de réplicas sea 0 o 1.

Creando un disco persistente GCE

Antes de poder usar un disco persistente GCE en un Pod, necesitas crearlo.

gcloud compute disks create --size=500GB --zone=us-central1-a my-data-disk

Ejemplo de configuración de un disco persistente GCE

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: test-container
      volumeMounts:
        - mountPath: /test-pd
          name: test-volume
  volumes:
    - name: test-volume
      # Este PD GCE debe existir con anterioridad.
      gcePersistentDisk:
        pdName: my-data-disk
        fsType: ext4

Discos regionales persistentes

La función de discos regionales persistentes permite la creación de discos persistentes que están disponibles en dos zonas dentro de la misma región. Para usar esta función, el volumen debe ser provisto como un PersistentVolumen; referenciar el volumen directamente desde un Pod no está soportado.

Aprovisionamiento manual de un PD PersistentVolume Regional

El aprovisionamiento dinámico es posible usando un StorageClass para el DP GCE. Antes de crear un PersistentVolume, debes crear el disco persistente:

gcloud compute disks create --size=500GB my-data-disk
  --region us-central1
  --replica-zones us-central1-a,us-central1-b

Ejemplo de configuración de un disco persistente regional

apiVersion: v1
kind: PersistentVolume
metadata:
  name: test-volume
spec:
  capacity:
    storage: 400Gi
  accessModes:
    - ReadWriteOnce
  gcePersistentDisk:
    pdName: my-data-disk
    fsType: ext4
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: failure-domain.beta.kubernetes.io/zone
              operator: In
              values:
                - us-central1-a
                - us-central1-b

Migración CSI GCE

FEATURE STATE: Kubernetes v1.17 [beta]

La función CSIMigration para el DP GCE, cuando se habilita, redirige todas las operaciones de complemento desde el complemento existente dentro del árbol existente al controlador de Interfaz de Almacenamiento del Contenedor (CSI) de pd.csi.storage.gke.io. Para poder usar esta función, el controlador PD GCE debe ser instalado en el clúster y habilitar las funciones beta CSIMigration y CSIMigrationGCE.

gitRepo (deprecado)

Un volumen gitRepo es un ejemplo de un complemento de volumen. Este complemento monta un directorio vacío y clona un repositorio git en este directorio para que tu Pod pueda usarlo.

Aquí un ejemplo de un volumen gitrepo:

apiVersion: v1
kind: Pod
metadata:
  name: server
spec:
  containers:
    - image: nginx
      name: nginx
      volumeMounts:
        - mountPath: /mypath
          name: git-volume
  volumes:
    - name: git-volume
      gitRepo:
        repository: "git@somewhere:me/my-git-repository.git"
        revision: "22f1d8406d464b0c0874075539c1f2e96c253775"

glusterfs

Un volumen glusterfs permite montar un volumen Glusterfs en tu Pod. A diferencia de emptyDir, que se borra cuando se remueve un Pod, el contenido de un volumen glusterfs es preservado y el volumen solamente se desmonta. Esto significa que un volumen glusterfs puede ser pre-poblado con datos, y que los datos pueden ser compartidos entre pods. GlusterFS puede ser montado por múltiples escritores simultáneamente.

Mira el ejemplo de GlusterFS para más detalles.

hostPath

Un volumen hostPath monta un archivo o un directorio del sistema de archivos del nodo host a tu Pod. Esto no es algo de muchos Pods necesiten, pero ofrece una trampa de escape poderosa para algunas aplicaciones.

Por ejemplo, algunos usos de un hostPath son:

  • ejecutar un contenedor que necesita acceso a los directorios internos de Docker, usa un hostPath de /var/lib/docker
  • ejecutar un cAdvisor en un contenedor; usa un hostPath de /sys
  • permitir a un Pod especificar si un hostPath dado debería existir ante de correr el Pod, si debe crearse, cómo debe existir

Además de la propiedad requerida path, puedes especificar opcionalmente un tipopara un volumen hostPath.

Los valores soportados para el campo tipo son:

Valor Comportamiento
Una cadena vacía (por defecto) es para compatibilidad con versiones anteriores, lo que significa que no se harán revisiones antes de montar el volumen hostPath.
DirectoryOrCreate Si no hay nada en la ruta dada, se creará un directorio vacío como es requerido con los permisos a 0755, teniendo el mismo grupo y propiedad que el Kubelet.
Directory Un directorio debe existir en la ruta dada
FileOrCreate Si no hay nada en la ruta dada, se creará un archivo vacío como es requerido con los permisos a 0644, teniendo el mismo grupo y propiedad que el Kubelet.
File Un archivo debe existir en la ruta dada
Socket Un socket de UNIX debe existir en la ruta dada
CharDevice Un dispositivo de caracteres debe existir en la ruta data
BlockDevice Un dispositivo de bloques dbe existir en la ruta dada

Ten cuidado cuando uses este tipo de volumen, porque:

  • Los Pods con configuración idéntica (tales como los creados por un PodTemplate) pueden comportarse de forma distinta en nodos distintos debido a diferentes ficheros en los nodos.
  • Los ficheros o directorios creados en los hosts subyacentes son modificables solo por root. Debes ejecutar tu proceso como root en un Contenedor privilegiado o modificar los permisos de archivo en el host para escribir a un volumen hostPath

Ejemplo de configuración hostPath

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: test-container
      volumeMounts:
        - mountPath: /test-pd
          name: test-volume
  volumes:
    - name: test-volume
      hostPath:
        # localización del directorio en el host
        path: /data
        # este campo es opcional
        type: Directory

ejemplo de configuración hostPath FileOrCreate

apiVersion: v1
kind: Pod
metadata:
  name: test-webserver
spec:
  containers:
    - name: test-webserver
      image: k8s.gcr.io/test-webserver:latest
      volumeMounts:
        - mountPath: /var/local/aaa
          name: mydir
        - mountPath: /var/local/aaa/1.txt
          name: myfile
  volumes:
    - name: mydir
      hostPath:
        # Asegúrate que el directorio del archivo es creado.
        path: /var/local/aaa
        type: DirectoryOrCreate
    - name: myfile
      hostPath:
        path: /var/local/aaa/1.txt
        type: FileOrCreate

iscsi

Un volumen iscsi permite que se monte un volumen ISCSI (SCSI sobre IP) existente en tu Pod. A diferencia de emptydir, que es removido cuando se remueve un Pod, el contenido de un volumen iscsi es preservado y el volumen solamente se desmonta. Esto significa que un volumen iscsi puede ser pre-poblado con datos, y que estos datos se pueden compartir entre pods.

Una función de SCSI es que puede ser montado como de solo lectura por múltiples consumidores simultáneamente. Esto significa que puedes pre-poblar un volumen con tu conjunto de datos y servirlo en paralelo para tantos Pods como necesites. Desafortunadamente, los volúmenes ISCSI solo se pueden montar por un único consumidor en modo lectura-escritura. Escritores simultáneos no está permitido.

Mira el ejemplo iSCSI para más detalles.

local

Un volumen local representa un dispositivo de almacenamiento local como un disco, una partición o un directorio.

Los volúmenes locales solo se pueden usar como un PersistenVolume creado estáticamente. El aprovisionamiento dinámico no está soportado.

Comparados con volúmenes hostPath, los volúmenes local se usan de manera duradera y portátil sin programar pods manualmente a los nodos. El sistema está consciente de las limitaciones del nodo del volumen al mirar la afinidad del nodo en el PersistenVolumen.

Sin embargo, los volúmenes localestán sujetos a la disponibilidad del nodo subyacente y no son compatibles para todas las aplicaciones.

Si un nodo deja de estar sano, entonces el volumen local se vuelve inaccesible al Pod. El Pod que utiliza este volumen no se puede ejecutar. Las aplicaciones que usan volúmenes local deben ser capaces de tolerar esta disponibilidad reducida, así como la pérdida potencial de datos, dependiendo de las características de durabilidad del disco subyacente.

El siguiente ejemplo muestra un PersistentVolume usando un volumen localy nodeAffinity:

apiVersion: v1
kind: PersistentVolume
metadata:
  name: example-pv
spec:
  capacity:
    storage: 100Gi
  volumeMode: Filesystem
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Delete
  storageClassName: local-storage
  local:
    path: /mnt/disks/ssd1
  nodeAffinity:
    required:
      nodeSelectorTerms:
        - matchExpressions:
            - key: kubernetes.io/hostname
              operator: In
              values:
                - example-node

Debes establecer un valor de nodeAffinity del PersistenVolume cuando uses volúmenes local. El Scheduler de Kubernetes usa nodeaffinity del PersistenVolume para programar estos Pods al nodo correcto.

El volumeMode del PersistentVolume se puede establecer en "Block" (en lugar del valor por defecto, "Filesystem") para exponer el volumen local como un dispositivo de bloque sin formato.

Cuando usas volúmenes locales, se recomienda crear un StorageClass con volumeBindingMode en WaitForFirstConsumer. Para más detalles, mira el ejemplo de StorageClass. Retrasar el enlace con el volumen asegura que la decisión del PersistenVolumeClaim sea evaluada con otras limitaciones que el Pod pueda tener, tales como requisitos de recursos del nodo, selectores de nodo, afinidad del Pod, y anti-afinidad del Pod.

Se puede ejecutar un aprovisionador estático externo para un manejo mejorado del ciclo de vida del volumen local. Ten en cuenta que este aprovisionador no soporta aprovisionamiento dinámico todavía. Para un ejemplo de un aprovisionador local externo, mira la guía de usuario de aprovisionador de volumen local

nfs

Un volumen nfs permite montar un NFS (Sistema de Ficheros de Red) compartido en tu Pod. A diferencia de emptyDir que se borra cuando el Pod es removido, el contenido de un volumen nfs solamente se desmonta. Esto significa que un volumen NFS puede ser pre-poblado con datos, y que estos datos puedes ser compartidos entre pods. NFS puede ser montado por múltiples escritores simultáneamente.

Mira el ejemplo NFS para más información.

persistentVolumeClaim

Un volumen persistenceVolumeClain se utiliza para montar un PersistentVolume en tu Pod. PersistentVolumeClaims son una forma en que el usuario "reclama" almacenamiento duradero (como un PersistentDisk GCE o un volumen ISCSI) sin conocer los detalles del ambiente de la nube en particular.

Mira la información spbre PersistentVolumes para más detalles.

portworxVolume

Un portworxVolume es un almacenamiento de bloque elástico que corre hiperconvergido con Kubernetes. Almacenamiento de huellas de Portworx en un servidor, niveles basados en capacidades y capacidad agregada en múltiples servidores. Portworx se ejecuta como invitado en máquinas virtuales o en nodos Linux nativos.

Un portworxVolume puede ser creado dinámicamente a través de Kubernetes o puede ser pre-aprovisionado y referido dentro de un Pod. Aquí un Pod de ejemplo refiriendo a un volumen Portworx pre-aprovisionado:

apiVersion: v1
kind: Pod
metadata:
  name: test-portworx-volume-pod
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: test-container
      volumeMounts:
        - mountPath: /mnt
          name: pxvol
  volumes:
    - name: pxvol
      # Este volumen portworx debe sxistir con anterioridad.
      portworxVolume:
        volumeID: "pxvol"
        fsType: "<fs-type>"

Para más detalles, mira los ejemplos de volumen Portworx.

projected

Un volumen projected mapea distintas fuentes de volúmenes existentes en un mismo directorio.

Actualmente, se pueden los siguientes tipos de volúmenes:

Se requiere que todas las fuentes estén en el mismo namespace que el Pod. Para más detalles mira el all-in-one volume design document.

Configuración de ejemplo con un secret, un downwardAPI, y un configMap

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
    - name: container-test
      image: busybox
      volumeMounts:
        - name: all-in-one
          mountPath: "/projected-volume"
          readOnly: true
  volumes:
    - name: all-in-one
      projected:
        sources:
          - secret:
              name: mysecret
              items:
                - key: username
                  path: my-group/my-username
          - downwardAPI:
              items:
                - path: "labels"
                  fieldRef:
                    fieldPath: metadata.labels
                - path: "cpu_limit"
                  resourceFieldRef:
                    containerName: container-test
                    resource: limits.cpu
          - configMap:
              name: myconfigmap
              items:
                - key: config
                  path: my-group/my-config

Configuración de ejemplo: secrets con un modo de permisos no predeterminados

apiVersion: v1
kind: Pod
metadata:
  name: volume-test
spec:
  containers:
    - name: container-test
      image: busybox
      volumeMounts:
        - name: all-in-one
          mountPath: "/projected-volume"
          readOnly: true
  volumes:
    - name: all-in-one
      projected:
        sources:
          - secret:
              name: mysecret
              items:
                - key: username
                  path: my-group/my-username
          - secret:
              name: mysecret2
              items:
                - key: password
                  path: my-group/my-password
                  mode: 511

Cada volumen proyectado está listado en spec bajo sources. Los parámetros son casi los mismos salvo dos excepciones:

  • Para los secrets, el campo secretName ha sido cambiado a name para ser consistente con el nombre del configMap.
  • El defaultMode solo se puede especificar en el nivel proyectado y no para cada fuente de volumen. Sin, como se muestra arriba, puedes establecer explícitamente el mode para cada proyección individual.

Cuando la función TokenRequestProjection está habilitada, puedes inyectar el token para el service account actual en un Pod en la ruta especificada. Por ejemplo:

apiVersion: v1
kind: Pod
metadata:
  name: sa-token-test
spec:
  containers:
    - name: container-test
      image: busybox
      volumeMounts:
        - name: token-vol
          mountPath: "/service-account"
          readOnly: true
  volumes:
    - name: token-vol
      projected:
        sources:
          - serviceAccountToken:
              audience: api
              expirationSeconds: 3600
              path: token

El Pod de ejemplo tiene un volumen proyectado que contiene el token del serviceAccount inyectado. Este token se puede usar por el contenedor de un Pod para acceder a la API del servidor de Kubernetes. El audience contiene la audiencia dirigida del token. Un recipiente del token debe identificarse a sí mismo con un identificador especificado en la audiencia del token, de lo contrario debería rechazar el token. Este campo es opcional y por defecto tiene el valor del identificador del servidor API.

EL campo expirationSeconds es la duración esperada de la validez del token del serviceAccount. Su valor por defecto es 1 hora y debe ser al menos 10 minutos (600 segundos). Un administrador puede limitar su valor máximo al especificar la opción --service-account-max-token-expiration para el servidor API. El campo path especifica una ruta relativa al punto de montaje del volumen proyectado.

quobyte

Un volumen quobyte permite montar un volumen Quobyte en tu Pod.

Quobyte soporta el Container Storage Interface. CSI es el complemento recomendado para usar Quobyte dentro de Kubernetes. El proyecto Github de Quobyte tiene instrucciones para desplegar usando CSI, junto con ejemplos.

rbd

Un volumen rbd permite montar un volumen Rados Block Device (RBD) en tu Pod. A diferencia de emptyDir, que se borra cuando el Pod es removido, el contenido de un volumen rbd es preservado y el volumen se desmonta. Esto significa que un volumen RBD puede ser pre-poblado con datos, y que estos datos pueden ser compartidos entre pods.

Una función de RBD es que solo se puede montar como de solo lectura por múltiples consumidores simultáneamente. Esto significa que puedes pre-poblar un volumen con tu conjunto de datos y luego servirlo en paralelo desde tantos pods como necesites. Desafortunadamente, los volúmenes RBD solo se pueden montar por un único consumidor en modo lectura-escritura. No se permiten escritores simultáneos.

Mira el ejemplo RBD para más detalles.

scaleIO (deprecado)

ScaleIO es una plataforma de almacenamiento basada en software que usa el hardware existente para crear clústeres de almacenamiento en red de bloques compartidos escalables. El complemento de volumen scaleIO permite a los pods desplegados acceder a volúmenes existentes ScaleIO. Para información acerca de aprovisionamiento dinámico de nuevos persistence volumen claims, mira ScaleIO persistent volumes

El siguiente ejemplo es una configuración de un Pod con ScaleIO:

apiVersion: v1
kind: Pod
metadata:
  name: pod-0
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: pod-0
      volumeMounts:
        - mountPath: /test-pd
          name: vol-0
  volumes:
    - name: vol-0
      scaleIO:
        gateway: https://localhost:443/api
        system: scaleio
        protectionDomain: sd0
        storagePool: sp1
        volumeName: vol-0
        secretRef:
          name: sio-secret
        fsType: xfs

Para más detalles, mira los ejemplos de ScaleIO

secret

Un volumen seret se utiliza para pasar información sensible, como contraseñas, a los Pods. Puedes guardar secrets en la API de Kubernetes y montarlos como ficheros para usarlos con los pods sin acoplarlos con Kubernetes directamente. Los volúmenes secret son respaldados por tmpfs (un sistema de ficheros respaldado por la RAM) así que nunca se escriben en un almacenamiento no volátil.

Para más detalles, mira Configurando Secrets.

storageOS

Un volumen storageos permite montar un volumen existente StorageOS en tu Pod.

StorageOS corre como un contenedor dentro de tu contenedor Kubernetes, haciendo accesible el almacenamiento local o adjunto desde cualquier node dentro del cluster de Kubernetes. Los datos pueden ser replicados para protegerlos contra fallos del nodo. Este aprovisionamiento y compresión pueden mejorar el uso y reducir costes.

El contenedor StorageOs requiere Linux de 64 bits y no tiene dependencias adicionales. Una licencia gratuita para desarrolladores está disponible.

El siguiente ejemplo es una configuración de un Pod con Storage OS:

apiVersion: v1
kind: Pod
metadata:
  labels:
    name: redis
    role: master
  name: test-storageos-redis
spec:
  containers:
    - name: master
      image: kubernetes/redis:v1
      env:
        - name: MASTER
          value: "true"
      ports:
        - containerPort: 6379
      volumeMounts:
        - mountPath: /redis-master-data
          name: redis-data
  volumes:
    - name: redis-data
      storageos:
        # El volumen `redis-vol01` debe existir dentro de StorageOS en el namespace `default`.
        volumeName: redis-vol01
        fsType: ext4

Para más información sobre StorageOS, aprovisionamiento dinámico, y PersistentVolumeClaims, mira los ejemplos de StorageOS examples.

vsphereVolume

Un volumen vsphereVolume se usa para montar un volumen VMDK vSphere en tu Pod. El contenido de un volumen es preservado cuando se desmonta. Tiene soporte para almacén de datos VMFS y VSAN.

Creando un volumen VMDK

Elige uno de los siguientes métodos para crear un VMDK.

Primero entra mediante ssh en ESX, luego usa uno de los siguientes comandos para crear un VMDK:

vmkfstools -c 2G /vmfs/volumes/DatastoreName/volumes/myDisk.vmdk

Usa el siguiente comando para crear un VMDK:

vmware-vdiskmanager -c -t 0 -s 40GB -a lsilogic myDisk.vmdk

Ejemplo de configuración vSphere VMDK

apiVersion: v1
kind: Pod
metadata:
  name: test-vmdk
spec:
  containers:
    - image: k8s.gcr.io/test-webserver
      name: test-container
      volumeMounts:
        - mountPath: /test-vmdk
          name: test-volume
  volumes:
    - name: test-volume
      # Este volumen VMDK ya debe existir.
      vsphereVolume:
        volumePath: "[DatastoreName] volumes/myDisk"
        fsType: ext4

Para mayor información, mira el ejemplo de vSphere volume.

Migración CSI vSphere

FEATURE STATE: Kubernetes v1.19 [beta]
Cuando la función CSIMigration está habilitada, redirige todas las operaciones de complemento desde el complemento existente en el árbol al controlador CSI csi.vsphere.vmware.com. Para usar esta función, el controlador vSphere CSI debe estar instalado en el clúster y las feature gates CSIMigration y CSIMigrationvSphere deben estar habilitadas.

Esto también requiere que la versión de vSphere vCenter/ESXi sea la 7.0u1 y la versión mínima de HW version sea VM versión 15.

migración completa de vSphere CSI

FEATURE STATE: Kubernetes v1.19 [beta]
Para apagar el complemento vsphereVolume y no cargarlo por el administrador del controlador y el kubelet, necesitas establecer eta función a true. Debes instalar un controlador de tipo csi.vsphere.vmware.com en todos los nodos worker.

Uso de subPath

Algunas veces es útil compartir un volumen para múltiples usos en un único Pod. La propiedad volumeMounts.subPath especifica una sub-ruta dentro del volumen referenciado en lugar de su raíz.

El siguiente ejemplo muestra cómo configurar un Pod con la pila LAMP (Linux Apache MySQL PHP) usando un único volumen compartido. Esta configuración de ejemplo usando subPath no se recomienda para su uso en producción.

El código de la aplicación PHP y los recursos apuntan al directorio html del volumen y la base de datos MySQL se almacena en el directorio mysql. Por ejemplo: The PHP application's code and assets map to the volume's html folder and the MySQL database is stored in the volume's mysql folder. For example:

apiVersion: v1
kind: Pod
metadata:
  name: my-lamp-site
spec:
  containers:
    - name: mysql
      image: mysql
      env:
        - name: MYSQL_ROOT_PASSWORD
          value: "rootpasswd"
      volumeMounts:
        - mountPath: /var/lib/mysql
          name: site-data
          subPath: mysql
    - name: php
      image: php:7.0-apache
      volumeMounts:
        - mountPath: /var/www/html
          name: site-data
          subPath: html
  volumes:
    - name: site-data
      persistentVolumeClaim:
        claimName: my-lamp-site-data

Uso de subPath con variables de entorno expandidas

FEATURE STATE: Kubernetes v1.17 [stable]
Usa el campo subPathExpr para construir un nombre de directorio subPath desde variables de entorno de la API. Las propiedades subPath y subPathExpr son mutuamente exclusivas.

En este ejemplo, un Pod usa subPathExpr para crear un directorio pod1 dentro del volumen hostPath var/logs/pods. El volumen hostPath toma el nombre del Pod desde la downwardAPI. El directorio anfitrión var/log/pods/pod1 se monta en /logs en el contenedor.

apiVersion: v1
kind: Pod
metadata:
  name: pod1
spec:
  containers:
    - name: container1
      env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: metadata.name
      image: busybox
      command:
        [
          "sh",
          "-c",
          "while [ true ]; do echo 'Hello'; sleep 10; done | tee -a /logs/hello.txt",
        ]
      volumeMounts:
        - name: workdir1
          mountPath: /logs
          subPathExpr: $(POD_NAME)
  restartPolicy: Never
  volumes:
    - name: workdir1
      hostPath:
        path: /var/log/pods

Recursos

El medio de almacenamiento (como un disco o un SSD) de un volumen emptyDir se determina por el medio del sistema de archivos que contiene el directorio raíz del kubelet (típicamente /var/lib/kubelet). No hay límite de cuánto espacio puede consumir un volumen emptydir o hostPath, y no hay aislamiento entre contenedores o entre pods.

Para aprender más sobre requerir espacio usando una espacificación de recurso, mira cómo administrar recursos.

Complementos de volúmenes fuera del árbol

Los complementos de volumen fuera del árbol incluyen Container Storage Interface (CSI) y FlexVolume. Estos complementos permiten a los proveedores de almacenamiento crear complementos de almacenamiento personalizados sin añadir su código fuente al repositorio de Kubernetes.

Anteriormente, todos los complementos de volumen estaban "en el árbol". Los complementos "en el árbol" se construían, enlazaban, compilaban y enviaban con los binarios del núcleo de Kubernetes. Esto significaba que agregar un nuevo sistema de almacenamiento a Kubernetes (un complemento de volumen) requería verificar el código en el repositorio de código del núcleo de Kubernetes.

Tanto CSI como FlexVolume permiten que se desarrollen complementos de volúmenes independientemente del código base de Kubernetes, y se desplieguen (instalen) en los clústeres de Kubernetes como extensiones.

Para los proveedores de almacenamiento que buscan crear un complemento de volumen fuera del árbol, por favor refiéranse a Preguntas frecuentees de complementos de volumen.

csi

La interfaz de almacenamiento del contenedor (CSI) define una interfaz estándar para sistemas de orquestación del contenedor (como Kubernetes) para exponer sistemas de almacenamiento arbitrario a sus cargas de trabajo del contenedor.

Por favor, lee la propuesta de diseño CSI para más información.

Una vez que se despliega un controlador de volumen CSI compatible, los usuarios pueden usar el tipo de volumen csi para adjuntar o montar los volúmenes expuestos por el controlador CSI.

Un volumen csi puede ser usado en un Pod en tres maneras distintas:

Los siguientes campos están disponibles para que los administradores de almacenamiento configuren el volumen persistente CSI

  • driver: Un valor de cadena de caracteres que especifica el nombre del controlador de volumen a usar. Este valor debe corresponder al valor de respuesta en el GetPluginInfoResponse por el controlador CSI tal como se define en la especificación CSI. Es usado por Kubernetes para identificar cuál controlador llamar, y por los componentes del controlador CSI para identificar cuáles objetos PV pertenecen al controlador CSI.
  • volumenHandle: Un valor de cadena de caracteres que identifica el volumen unívocamente. Este valor debe corresponder al valor en el campo volumen.id del CreateVolumeResponse por el controlador CSI como se define en la especificación CSI spec. El valor es pasado como volume.id en todas las llamadas al controlador de volumen CSI cuando referencias el volumen.
  • readOnly: Un valor booleano opcional que indica si el volumen es para ser "ControllerPublished" (adjuntado) como solo lectura. Por defecto es falso. Este valor es pasado el controlador CSI en el campo readOnly en el ControllerPublishVolumeRequest.
  • fsType: Si el VolumeModedel PV es Filesystem entonces este campo se puede usar para especificar el sistema de archivos que debería usarse para montar el volumen. Si el volumen no ha sido formateado y soportado, este valor se utilizará para formatear el volumen. Este valor se para al controlador CSI con el campo VolumeCapability de ControllerPublishVolumeRequest, NodeStageVolumeRequest, y NodePublishVolumeRequest.
  • volumeAttributes: Un mapa de cadena de caracteres que especifica las propiedades estáticas de un volumen. Este mapa debe corresponder al map devuelto por el campo volume.attributes del CreateVolumeResponse por el controlador CSI tal como se define en la especificación CSI spec. El mapa es pasado al controlador CSI con el campo volume.context en el ControllerPublishVolumeRequest, NodeStageVolumeRequest, y NodePublishVolumeRequest.
  • controllerPublishSecretRef: Una referencia al objeto secret que contiene información sensible para pasar al controlador CSI para completar las llamadas CSI ControllerPublishVolume y ControllerUnpublishVolume. Este campo es opcional, y puede estar vacío si no se requiere un secret. Si el Secret contiene más de un secret, se pasan todos los secrets.
  • nodeStageSecretRef: Una referencia al objeto secret que contiene información sensible a pasar al controlador CSI para completar la llamada CSI NodeStageVolume. Este ampo es opcional, y puede estar vacío si no se requiere un secret. Si el Secret contiene más de un secret, todos los secrets son pasados.
  • nodePublishSecretRef: Una referencia al objeto que contiene información sensible a pasar al controlador CSI para completar la llamada CSI NodePublishVolume. Este ampo es opcional, y puede estar vacío si no se requiere un secret. Si el Secret contiene más de un secret, todos los secrets son pasados.

Soporte de volumen CSI de fila de bloques

FEATURE STATE: Kubernetes v1.18 [stable]

Los proveedores con controladores CSI externos pueden implementar soporte de volumen de bloques sin procesar en cargas de trabajo de Kubernetes.

Puedes configurar tu You can set up your PersistentVolume/PersistentVolumeClaim with raw block volume support como de costumbre, sin ningún cambio específico CSI.

Volúmenes efímeros CSI

FEATURE STATE: Kubernetes v1.16 [beta]

Puedes configurar directamente volúmenes CSI dentro de la especificación del Pod. Los volúmenes especificados de esta manera son efímeros y no se persisten entre reinicios del Pod. Mira Volúmenes efímeros para más información.

Para más información de cómo desarrollador un controlador CSI, mira la documentación kubernetes-csi

Migrando a controladores CSI desde complementos en el árbol.

FEATURE STATE: Kubernetes v1.17 [beta]
La función CSIMigration, cuando está habilitada, dirige todas las operaciones hacia complementos existentes en el árbol a complementos CSI correspondientes (que se espera que estén instalados y configurados). Como resultado, los operadores no tienen que hacer ningún cambio de configuración a las clases de almacenamiento, PersistentVolumes o PersistentVolumeClaims (refiriéndose a complementos en el árbol) cuando haces la transición a un controlador CSI que un reemplaza complemento en el árbol.

Las operaciones y funciones que están soportadas incluye: aprovisionamiento/borrado, adjuntar/separar, montar/desmontar y redimensionar volúmenes.

In-tree plugins that support CSIMigration and have a corresponding CSI driver implemented are listed in Types of Volumes.

flexVolume

FlexVolume is an out-of-tree plugin interface that has existed in Kubernetes since version 1.2 (before CSI). It uses an exec-based model to interface with drivers. The FlexVolume driver binaries must be installed in a pre-defined volume plugin path on each node and in some cases the control plane nodes as well.

Pods interact with FlexVolume drivers through the flexvolume in-tree volume plugin. For more details, see the FlexVolume examples.

Propagación del montaje

La propagación del montaje permite compartir volúmenes montados por un contenedor para otros contenedores en el mismo Pod, o aun para otros pods en el mismo nodo.

La propagación del montaje de un volumen es controlada por el campo mountPropagation en Container.volumeMounts. Sus valores son:

  • None - Este montaje de volumen no recibirá ningún montaje posterior que el host haya montado en este volumen o en cualquiera de sus subdirectorios. De manera similar, los montajes creados por el contenedor no serán visibles en el host. Este es el modo por defecto.

    Este modo es igual la propagación del montaje private tal como se describe en la documentación Linux kernel documentation

  • HostToContainer - Este montaje de volumen recibirá todos los montajes subsecuentes que son montados a este volumen o cualquiera de sus subdirectorios.

    En otras palabras, si el host monta algo dentro del montaje del volumen, el contenedor lo verá montado allí.

    De manera similar, si cualquier Pod con propagación de montaje Bidirectional al mismo volumen monta algo allí, el contenedor con propagación de montaje HostToContainer lo verá.

    Este modo es igual a la propagación de montaje rslave tal como se describe en la documentación del kernel de Linux

  • Bidirectional- Este montaje de volumen se comporta de la misma manera de el montajeHostToContainer. Adicionalmente, todos los montajes de volúmenes creados por el contenedor serán propagados de vuelta al host y a todos los contenedores de todos los pods que usan el mismo volumen.

    Un uso típico para este modo es un Pod con un FlexVolumen o un controlador CSI o un Pod que necesita montar al en el host usando un volumen hostPath.

    Este modo es igual a la propagación de montaje rshared tal como se describe en la documentación del kernel de Linux documentación

Configuration

Before mount propagation can work properly on some deployments (CoreOS, RedHat/Centos, Ubuntu) mount share must be configured correctly in Docker as shown below.

Edit your Docker's systemd service file. Set MountFlags as follows:

MountFlags=shared

Or, remove MountFlags=slave if present. Then restart the Docker daemon:

sudo systemctl daemon-reload
sudo systemctl restart docker

Siguientes pasos

Sigue un ejemplo de desplegar WordPrss y MySQL con volúmenes persistentes.

2 - Snapshots de Volúmenes

En Kubernetes, un VolumeSnapshot representa un Snapshot de un volumen en un sistema de almacenamiento. Este documento asume que está familiarizado con volúmenes persistentes de Kubernetes.

Introducción

Al igual que los recursos de API PersistentVolume y PersistentVolumeClaim se utilizan para aprovisionar volúmenes para usuarios y administradores, VolumeSnapshotContent y VolumeSnapshot se proporcionan para crear Snapshots de volumen para usuarios y administradores.

Un VolumeSnapshotContent es un Snapshot tomado de un volumen en el clúster que ha sido aprovisionado por un administrador. Es un recurso en el clúster al igual que un PersistentVolume es un recurso de clúster.

Un VolumeSnapshot es una solicitud de Snapshot de un volumen por parte del usuario. Es similar a un PersistentVolumeClaim.

VolumeSnapshotClass permite especificar diferentes atributos que pertenecen a un VolumeSnapshot. Estos atributos pueden diferir entre Snapshots tomados del mismo volumen en el sistema de almacenamiento y, por lo tanto, no se pueden expresar mediante el mismo StorageClass de un PersistentVolumeClaim.

Los Snapshots de volumen brindan a los usuarios de Kubernetes una forma estandarizada de copiar el contenido de un volumen en un momento determinado, sin crear uno completamente nuevo. Esta funcionalidad permite, por ejemplo, a los administradores de bases de datos realizar copias de seguridad de las bases de datos antes de realizar una edición o eliminar modificaciones.

Cuando utilicen esta función los usuarios deben tener en cuenta lo siguiente:

  • Los objetos de API VolumeSnapshot, VolumeSnapshotContent, y VolumeSnapshotClass son CRDs, y no forman parte de la API principal.
  • La compatibilidad con VolumeSnapshot solo está disponible para controladores CSI.
  • Como parte del proceso de implementación de VolumeSnapshot, el equipo de Kubernetes proporciona un controlador de Snapshot para implementar en el plano de control y un sidecar auxiliar llamado csi-snapshotter para implementar junto con el controlador CSI. El controlador de Snapshot observa los objetos VolumeSnapshot y VolumeSnapshotContent y es responsable de la creación y eliminación del objeto VolumeSnapshotContent. El sidecar csi-snapshotter observa los objetos VolumeSnapshotContent y activa las operaciones CreateSnapshot y DeleteSnapshot en un punto final CSI.
  • También hay un servidor webhook de validación que proporciona una validación más estricta en los objetos Snapshot. Esto debe ser instalado por las distribuciones de Kubernetes junto con el controlador de Snapshots y los CRDs, no los controladores CSI. Debe instalarse en todos los clústeres de Kubernetes que tengan habilitada la función de Snapshot.
  • Los controladores CSI pueden haber implementado o no la funcionalidad de Snapshot de volumen. Los controladores CSI que han proporcionado soporte para Snapshot de volumen probablemente usarán csi-snapshotter. Consulte CSI Driver documentation para obtener más detalles.
  • Los CRDs y las instalaciones del controlador de Snapshot son responsabilidad de la distribución de Kubernetes.

Ciclo de vida de un Snapshot de volumen y el contenido de un Snapshot de volumen.

VolumeSnapshotContents son recursos en el clúster. VolumeSnapshots son solicitudes de esos recursos. La interacción entre VolumeSnapshotContents y VolumeSnapshots sigue este ciclo de vida:

Snapshot del volumen de aprovisionamiento

Hay dos formas de aprovisionar los Snapshots: aprovisionadas previamente o aprovisionadas dinámicamente.

Pre-aprovisionado

Un administrador de clúster crea una serie de VolumeSnapshotContents. Llevan los detalles del Snapshot del volumen real en el sistema de almacenamiento que está disponible para que lo utilicen los usuarios del clúster. Existen en la API de Kubernetes y están disponibles para su consumo.

Dinámica

En lugar de utilizar un Snapshot preexistente, puede solicitar que se tome una Snapshot dinámicamente de un PersistentVolumeClaim. El VolumeSnapshotClass especifica los parámetros específicos del proveedor de almacenamiento para usar al tomar una Snapshot.

Vinculante

El controlador de Snapshots maneja el enlace de un objeto VolumeSnapshot con un objeto VolumeSnapshotContent apropiado, tanto en escenarios de aprovisionamiento previo como de aprovisionamiento dinámico. El enlace es un mapeo uno a uno.

En el caso de un enlace aprovisionado previamente, el VolumeSnapshot permanecerá sin enlazar hasta que se cree el objeto VolumeSnapshotContent solicitado.

Persistent Volume Claim como Snapshot Source Protection

El propósito de esta protección es garantizar que los objetos de la API PersistentVolumeClaim en uso, no se eliminen del sistema mientras se toma un Snapshot (ya que esto puede resultar en la pérdida de datos).

Mientras se toma un Snapshot de un PersistentVolumeClaim, ese PersistentVolumeClaim está en uso. Si elimina un objeto de la API PersistentVolumeClaim en uso activo como fuente de Snapshot, el objeto PersistentVolumeClaim no se elimina de inmediato. En cambio, la eliminación del objeto PersistentVolumeClaim se pospone hasta que el Snapshot esté readyToUse o se cancele.

Borrar

La eliminación se activa al eliminar el objeto VolumeSnapshot, y se seguirá la DeletionPolicy. Sí DeletionPolicy es Delete, entonces el Snapshot de almacenamiento subyacente se eliminará junto con el objeto VolumeSnapshotContent. Sí DeletionPolicy es Retain, tanto el Snapshot subyacente como el VolumeSnapshotContent permanecen.

VolumeSnapshots

Cada VolumeSnapshot contiene una especificación y un estado.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: new-snapshot-test
spec:
  volumeSnapshotClassName: csi-hostpath-snapclass
  source:
    persistentVolumeClaimName: pvc-test

persistentVolumeClaimName es el nombre de la fuente de datos PersistentVolumeClaim para el Snapshot. Este campo es obligatorio para aprovisionar dinámicamente un Snapshot.

Un Snapshot de volumen puede solicitar una clase particular especificando el nombre de un VolumeSnapshotClass utilizando el atributo volumeSnapshotClassName. Si no se establece nada, se usa la clase predeterminada si está disponible.

Para los Snapshots aprovisionadas previamente, debe especificar un volumeSnapshotContentName como el origen del Snapshot, como se muestra en el siguiente ejemplo. El campo de origen volumeSnapshotContentName es obligatorio para los Snapshots aprovisionados previamente.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: test-snapshot
spec:
  source:
    volumeSnapshotContentName: test-content

Contenido del Snapshot de volumen

Cada VolumeSnapshotContent contiene una especificación y un estado. En el aprovisionamiento dinámico, el controlador común de Snapshots crea objetos VolumeSnapshotContent. Aquí hay un ejemplo:

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
  name: snapcontent-72d9a349-aacd-42d2-a240-d775650d2455
spec:
  deletionPolicy: Delete
  driver: hostpath.csi.k8s.io
  source:
    volumeHandle: ee0cfb94-f8d4-11e9-b2d8-0242ac110002
  volumeSnapshotClassName: csi-hostpath-snapclass
  volumeSnapshotRef:
    name: new-snapshot-test
    namespace: default
    uid: 72d9a349-aacd-42d2-a240-d775650d2455

volumeHandle es el identificador único del volumen creado en el backend de almacenamiento y devuelto por el controlador CSI durante la creación del volumen. Este campo es obligatorio para aprovisionar dinámicamente un Snapshot. Especifica el origen del volumen del Snapshot.

Para los Snapshots aprovisionados previamente, usted (como administrador del clúster) es responsable de crear el objeto VolumeSnapshotContent de la siguiente manera.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
  name: new-snapshot-content-test
spec:
  deletionPolicy: Delete
  driver: hostpath.csi.k8s.io
  source:
    snapshotHandle: 7bdd0de3-aaeb-11e8-9aae-0242ac110002
  volumeSnapshotRef:
    name: new-snapshot-test
    namespace: default

snapshotHandle es el identificador único del Snapshot de volumen creado en el backend de almacenamiento. Este campo es obligatorio para las Snapshots aprovisionadas previamente. Especifica el ID del Snapshot CSI en el sistema de almacenamiento que representa el VolumeSnapshotContent.

Aprovisionamiento de Volúmenes a partir de Snapshots

Puede aprovisionar un nuevo volumen, rellenado previamente con datos de una Snapshot, mediante el campo dataSource en el objeto PersistentVolumeClaim.

Para obtener más detalles, consulte Volume Snapshot and Restore Volume from Snapshot.

3 - Clonación de volumen CSI

Este documento describe el concepto para clonar volúmenes CSI existentes en Kubernetes. Se sugiere estar familiarizado con Volúmenes.

Introducción

La función de clonación de volumen CSI agrega soporte para especificar PVCs existentes en el campo dataSource para indicar que un usuario desea clonar un Volume.

Un Clon se define como un duplicado de un volumen de Kubernetes existente que se puede consumir como lo sería cualquier volumen estándar. La única diferencia es que al aprovisionar, en lugar de crear un "nuevo" Volumen vacío, el dispositivo de backend crea un duplicado exacto del Volumen especificado.

La implementación de la clonación, desde la perspectiva de la API de Kubernetes, agrega la capacidad de especificar un PVC existente como dataSource durante la creación de un nuevo PVC. El PVC de origen debe estar vinculado y disponible (no en uso).

Los usuarios deben tener en cuenta lo siguiente cuando utilicen esta función:

  • El soporte de clonación (VolumePVCDataSource) sólo está disponible para controladores CSI.
  • El soporte de clonación sólo está disponible para aprovisionadores dinámicos.
  • Los controladores CSI pueden haber implementado o no la funcionalidad de clonación de volúmenes.
  • Sólo puede clonar un PVC cuando existe en el mismo Namespace que el PVC de destino (el origen y el destino deben estar en el mismo Namespace).
  • La clonación sólo se admite dentro de la misma Clase de Almacenamiento.
    • El volumen de destino debe ser de la misma clase de almacenamiento que el origen
    • Se puede utilizar la clase de almacenamiento predeterminada y se puede omitir storageClassName en la especificación
  • La clonación sólo se puede realizar entre dos volúmenes que usan la misma configuración de VolumeMode (si solicita un volumen en modo de bloqueo, la fuente DEBE también ser en modo de bloqueo)

Aprovisionamiento

Los clones se aprovisionan como cualquier otro PVC con la excepción de agregar un origen de datos que hace referencia a un PVC existente en el mismo Namespace.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: clone-of-pvc-1
  namespace: myns
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: cloning
  resources:
    requests:
      storage: 5Gi
  dataSource:
    kind: PersistentVolumeClaim
    name: pvc-1

El resultado es un nuevo PVC con el nombre clone-of-pvc-1 que tiene exactamente el mismo contenido que la fuente especificada pvc-1.

Uso

Una vez disponible el nuevo PVC, el PVC clonado se consume igual que el resto de PVC. También se espera en este punto que el PVC recién creado sea un objeto independiente. Se puede consumir, clonar, tomar snapshots, o eliminar de forma independiente y sin tener en cuenta sus datos originales. Esto también implica que la fuente no está vinculada de ninguna manera al clon recién creado, también puede modificarse o eliminarse sin afectar al clon recién creado.

4 - Volume Snapshot Classes

Este documento describe el concepto de VolumeSnapshotClass en Kubernetes. Se sugiere estar familiarizado con Volume Snapshots y Storage Classes.

Introducción

Al igual que StorageClass proporciona a los administradores una forma de describir las “clases” de almacenamiento que ofrecen al aprovisionar un volumen, VolumeSnapshotClass proporciona una forma de describir las “clases” de almacenamiento al aprovisionar un Snapshot de volumen.

El Recurso VolumeSnapshotClass

Cada VolumeSnapshotClass contiene los campos driver, deletionPolicy, y parameters, que se utilizan cuando un VolumeSnapshot que pertenece a la clase, necesita aprovisionarse dinámicamente.

El nombre de un objeto VolumeSnapshotClass es significativo y es la forma en que los usuarios pueden solicitar una clase en particular. Los administradores establecen el nombre y parámetros de una clase cuando crean por primera vez objetos VolumeSnapshotClass; una vez creados los objetos no pueden ser actualizados.

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-hostpath-snapclass
driver: hostpath.csi.k8s.io
deletionPolicy: Delete
parameters:

Los administradores pueden especificar un VolumeSnapshotClass predeterminado para VolumeSnapshots que no solicitan ninguna clase en particular. Para definir la clase predeterminada agregue la anotación: snapshot.storage.kubernetes.io/is-default-class: "true".

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotClass
metadata:
  name: csi-hostpath-snapclass
  annotations:
    snapshot.storage.kubernetes.io/is-default-class: "true"
driver: hostpath.csi.k8s.io
deletionPolicy: Delete
parameters:

Driver

Las clases de Snapshot de volumen tienen un controlador que determina que complemento de volumen CSI se utiliza para aprovisionar VolumeSnapshots. Este campo debe especificarse.

DeletionPolicy

Las clases de Snapshot de volumen tienen un deletionPolicy. Permite configurar lo que sucede con un VolumeSnapshotContent cuando se va a eliminar el objeto VolumeSnapshot al que está vinculado. La deletionPolicy de una clase de Snapshot de volumen puede Retain o Delete. Este campo debe ser especificado.

Si la deletionPolicy es Delete, el Snapshot de almacenamiento subyacente se eliminará junto con el objeto VolumeSnapshotContent. Si deletionPolicy es Retain, tanto el Snapshot subyacente como VolumeSnapshotContent permanecerán.

Parameters

Las clases de Snapshot de volumen tienen parámetros que describen los Snapshots de volumen que pertenecen a la clase de Snapshot de volumen. Se pueden aceptar diferentes parámetros dependiendo del driver.

5 - Aprovisionamiento Dinámico de volumen

El aprovisionamiento dinámico de volúmenes permite crear volúmenes de almacenamiento bajo demanda. Sin el aprovisionamiento dinámico, los administradores de clústeres tienen que realizar llamadas manualmente a su proveedor de almacenamiento o nube para crear nuevos volúmenes de almacenamiento y luego crear objetos de PersistentVolume para representarlos en Kubernetes. La función de aprovisionamiento dinámico elimina la necesidad de que los administradores del clúster aprovisionen previamente el almacenamiento. En cambio, el aprovisionamiento ocurre automáticamente cuando los usuarios lo solicitan.

Antecedentes

La implementación del aprovisionamiento dinámico de volúmenes se basa en el objeto API StorageClass del grupo API storage.k8s.io. Un administrador de clúster puede definir tantos objetos StorageClass como sea necesario, cada uno especificando un volume plugin (aka provisioner) que aprovisiona un volumen y el conjunto de parámetros para pasar a ese aprovisionador. Un administrador de clúster puede definir y exponer varios tipos de almacenamiento (del mismo o de diferentes sistemas de almacenamiento) dentro de un clúster, cada uno con un conjunto personalizado de parámetros. Este diseño también garantiza que los usuarios finales no tengan que preocuparse por la complejidad y los matices de cómo se aprovisiona el almacenamiento, pero que aún tengan la capacidad de seleccionar entre múltiples opciones de almacenamiento.

Puede encontrar más información sobre las clases de almacenamiento aqui.

Habilitación del aprovisionamiento dinámico

Para habilitar el aprovisionamiento dinámico, un administrador de clúster debe crear previamente uno o más objetos StorageClass para los usuarios. Los objetos StorageClass definen qué aprovisionador se debe usar y qué parámetros se deben pasar a ese aprovisionador cuando se invoca el aprovisionamiento dinámico. El nombre de un objeto StorageClass debe ser un nombre de subdominio de DNS válido.

El siguiente manifiesto crea una clase de almacenamiento llamada "slow" que aprovisiona discos persistentes estándar similares a discos.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: slow
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-standard

El siguiente manifiesto crea una clase de almacenamiento llamada "fast" que aprovisiona discos persistentes similares a SSD.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast
provisioner: kubernetes.io/gce-pd
parameters:
  type: pd-ssd

Usar Aprovisionamiento Dinámico

Los usuarios solicitan almacenamiento aprovisionado dinámicamente al incluir una clase de almacenamiento en su PersistentVolumeClaim. Antes de Kubernetes v1.6, esto se hacía a través del la anotación volume.beta.kubernetes.io/storage-class. Sin embargo, esta anotación está obsoleta desde v1.9. Los usuarios ahora pueden y deben usar el campo storageClassName del objeto PersistentVolumeClaim. El valor de este campo debe coincidir con el nombre de un StorageClass configurada por el administrador (ver documentación).

Para seleccionar la clase de almacenamiento llamada "fast", por ejemplo, un usuario crearía el siguiente PersistentVolumeClaim:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: claim1
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: fast
  resources:
    requests:
      storage: 30Gi

Esta afirmación da como resultado que se aprovisione automáticamente un disco persistente similar a SSD. Cuando se elimina la petición, se destruye el volumen.

Comportamiento Predeterminado

El aprovisionamiento dinámico se puede habilitar en un clúster de modo que todas las peticiones se aprovisionen dinámicamente si no se especifica una clase de almacenamiento. Un administrador de clúster puede habilitar este comportamiento al:

Un administrador puede marcar un StorageClass específico como predeterminada agregando la anotación storageclass.kubernetes.io/is-default-class. Cuando existe un StorageClass predeterminado en un clúster y un usuario crea un PersistentVolumeClaim con storageClassName sin especificar, el controlador de admisión DefaultStorageClass agrega automáticamente el campo storageClassName que apunta a la clase de almacenamiento predeterminada.

Tenga en cuenta que puede haber como máximo una clase de almacenamiento default, o un PersistentVolumeClaim sin storageClassName especificado explícitamente.

Conocimiento de la Topología

En los clústeres Multi-Zone, los Pods se pueden distribuir en zonas de una región. Los backends de almacenamiento de zona única deben aprovisionarse en las zonas donde se programan los Pods. Esto se puede lograr configurando el Volume Binding Mode.

6 - Capacidad de Almacenamiento

La capacidad de almacenamiento es limitada y puede variar según el nodo en el que un Pod se ejecuta: es posible que no todos los nodos puedan acceder al almacenamiento conectado a la red o que, para empezar, el almacenamiento sea local en un nodo.

FEATURE STATE: Kubernetes v1.21 [beta]

Esta página describe cómo Kubernetes realiza un seguimiento de la capacidad de almacenamiento y cómo el planificador usa esa información para programar Pods en nodos que tienen acceso a suficiente capacidad de almacenamiento para los volúmenes restantes que faltan. Sin el seguimiento de la capacidad de almacenamiento, el planificador puede elegir un nodo que no tenga suficiente capacidad para aprovisionar un volumen y se necesitarán varios reintentos de planificación.

El seguimiento de la capacidad de almacenamiento es compatible con los controladores de la Interfaz de Almacenamiento de Contenedores (CSI) y necesita estar habilitado al instalar un controlador CSI.

API

Hay dos extensiones de API para esta función:

  • Los objetos CSIStorageCapacity: son producidos por un controlador CSI en el Namespace donde está instalado el controlador. Cada objeto contiene información de capacidad para una clase de almacenamiento y define qué nodos tienen acceso a ese almacenamiento.
  • El campo CSIDriverSpec.StorageCapacity: cuando se establece en true, el Planificador de Kubernetes considerará la capacidad de almacenamiento para los volúmenes que usan el controlador CSI.

Planificación

El planificador de Kubernetes utiliza la información sobre la capacidad de almacenamiento si:

  • la Feature gate de CSIStorageCapacity es true,
  • un Pod usa un volumen que aún no se ha creado,
  • ese volumen usa un StorageClass que hace referencia a un controlador CSI y usa el [modo de enlace de volumen] (/docs/concepts/storage/storage-classes/#volume-binding-mode)WaitForFirstConsumer, y
  • el objeto CSIDriver para el controlador tiene StorageCapacity establecido en true.

En ese caso, el planificador sólo considera los nodos para el Pod que tienen suficiente almacenamiento disponible. Esta verificación es muy simplista y solo compara el tamaño del volumen con la capacidad indicada en los objetos CSIStorageCapacity con una topología que incluye el nodo.

Para los volúmenes con el modo de enlace de volumen Immediate, el controlador de almacenamiento decide dónde crear el volumen, independientemente de los pods que usarán el volumen. Luego, el planificador programa los pods en los nodos donde el volumen está disponible después de que se haya creado.

Para los volúmenes efímeros de CSI, la planificación siempre ocurre sin considerar la capacidad de almacenamiento. Esto se basa en la suposición de que este tipo de volumen solo lo utilizan controladores CSI especiales que son locales a un nodo y no necesitan allí recursos importantes.

Replanificación

Cuando se selecciona un nodo para un Pod con volúmenes WaitForFirstConsumer, esa decisión sigue siendo tentativa. El siguiente paso es que se le pide al controlador de almacenamiento CSI que cree el volumen con una pista de que el volumen está disponible en el nodo seleccionado.

Debido a que Kubernetes pudo haber elegido un nodo basándose en información de capacidad desactualizada, es posible que el volumen no se pueda crear realmente. Luego, la selección de nodo se restablece y el planificador de Kubernetes intenta nuevamente encontrar un nodo para el Pod.

Limitaciones

El seguimiento de la capacidad de almacenamiento aumenta las posibilidades de que la planificación funcione en el primer intento, pero no puede garantizarlo porque el planificador tiene que decidir basándose en información potencialmente desactualizada. Por lo general, el mismo mecanismo de reintento que para la planificación sin información de capacidad de almacenamiento es manejado por los errores de planificación.

Una situación en la que la planificación puede fallar de forma permanente es cuando un pod usa varios volúmenes: es posible que un volumen ya se haya creado en un segmento de topología que luego no tenga suficiente capacidad para otro volumen. La intervención manual es necesaria para recuperarse de esto, por ejemplo, aumentando la capacidad o eliminando el volumen que ya se creó. Trabajo adicional para manejar esto automáticamente.

Habilitación del seguimiento de la capacidad de almacenamiento

El seguimiento de la capacidad de almacenamiento es una función beta y está habilitada de forma predeterminada en un clúster de Kubernetes desde Kubernetes 1.21. Además de tener la función habilitada en el clúster, un controlador CSI también tiene que admitirlo. Consulte la documentación del controlador para obtener más detalles.

Siguientes pasos

7 - Límites de Volumen específicos del Nodo

Esta página describe la cantidad máxima de Volúmenes que se pueden adjuntar a un Nodo para varios proveedores de nube.

Los proveedores de la nube como Google, Amazon y Microsoft suelen tener un límite en la cantidad de Volúmenes que se pueden adjuntar a un Nodo. Es importante que Kubernetes respete esos límites. De lo contrario, los Pods planificados en un Nodo podrían quedarse atascados esperando que los Volúmenes se conecten.

Límites predeterminados de Kubernetes

El Planificador de Kubernetes tiene límites predeterminados en la cantidad de Volúmenes que se pueden adjuntar a un Nodo:

Servicio de almacenamiento en la nubeVolúmenes máximos por Nodo
Amazon Elastic Block Store (EBS)39
Google Persistent Disk16
Microsoft Azure Disk Storage16

Límites personalizados

Puede cambiar estos límites configurando el valor de la variable de entorno KUBE_MAX_PD_VOLS y luego iniciando el Planificador. Los controladores CSI pueden tener un procedimiento diferente, consulte su documentación sobre cómo personalizar sus límites.

Tenga cuidado si establece un límite superior al límite predeterminado. Consulte la documentación del proveedor de la nube para asegurarse de que los Nodos realmente puedan admitir el límite que establezca.

El límite se aplica a todo el clúster, por lo que afecta a todos los Nodos.

Límites de Volumen dinámico

FEATURE STATE: Kubernetes v1.17 [stable]

Los límites de Volumen dinámico son compatibles con los siguientes tipos de Volumen.

  • Amazon EBS
  • Google Persistent Disk
  • Azure Disk
  • CSI

Para los Volúmenes administrados por in-tree plugins de Volumen, Kubernetes determina automáticamente el tipo de Nodo y aplica la cantidad máxima adecuada de Volúmenes para el Nodo. Por ejemplo:

  • En Google Compute Engine, se pueden adjuntar hasta 127 Volúmenes a un Nodo, según el tipo de Nodo.

  • Para los discos de Amazon EBS en los tipos de instancias M5,C5,R5,T3 y Z1D, Kubernetes permite que solo se adjunten 25 Volúmenes a un Nodo. Para otros tipos de instancias en Amazon Elastic Compute Cloud (EC2), Kubernetes permite adjuntar 39 Volúmenes a un Nodo.

  • En Azure, se pueden conectar hasta 64 discos a un Nodo, según el tipo de Nodo. Para obtener más detalles, consulte Sizes for virtual machines in Azure.

  • Si un controlador de almacenamiento CSI anuncia una cantidad máxima de Volúmenes para un Nodo (usando NodeGetInfo), el kube-scheduler respeta ese límite. Consulte las especificaciones de CSI para obtener más información.

  • Para los Volúmenes administrados por in-tree plugins que han sido migrados a un controlador CSI, la cantidad máxima de Volúmenes será la que informe el controlador CSI.