Blog

Migrando volúmenes EBS en kubernetes a EBS-CSI

En entornos de Kubernetes, los volúmenes persistentes desempeñan un papel crucial en el almacenamiento de datos de aplicaciones. Tener un entorno dinámico donde los recursos se crean y se destruyen de forma automática, es tan útil como peligroso si nuestros datos persistentes están entre estos recursos del cluster.

Uno de los almacenamientos más utilizados en entornos AWS es Amazon Elastic Block Store (EBS). En entornos de Kubernetes, gracias al controlador de almacenamiento externo EBS-CSI (EBS Container Storage Interface), tenemos la opción de utilizar volúmenes persistentes de EBS de manera eficiente y segura. La base radica en la capacidad de crear snapshots de volúmenes asociados a recursos de Kubernetes para manejarlos con facilidad.

En esta ocasión, explicaremos con un ejemplo cómo migrar volúmenes persistentes (PVC) a EBS-CSI en Kubernetes a partir de snapshots. Recordad que un snapshot de EBS es una copia puntual en el tiempo de un volumen EBS. Esto proporciona un mecanismo para respaldar y restaurar datos, así como para migrar volúmenes entre regiones o cuentas de AWS, procesos automatizados de disaster recovery, etc.

Debemos seguir los siguientes pasos para migrar los volúmenes de datos actuales al nuevo sistema EBS-CSI.

Paso 0: Preparación del cluster para uso de EBS CSI driver

Previamente nuestro cluster de Kubernetes debe tener instalado y configurado el controlador EBS-CSI, así como los CRDs necesarios para la gestión de snapshots y los StorageClass con los tipos de almacenamiento según nuestras necesidades.

Si queremos garantizar la integridad de los datos debemos parar y aislar el servicio, bien a nivel de red, o bien escalando los pods a cero manualmente.

Paso 1: Crear un nuevo snapshot del volúmen origen

Para ello, debemos primero obtener el volumeID del EBS inicial que tenemos configurado:


:~$ kubectl get pvc -n rabbitmq
NAME                              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
rabbitmq-data-rabbitmq-common-0   Bound    pvc-469ffaff-fa8e-46af-ad10-xxxxxxxxxxx   10Gi       RWO            gp2            44


:~$ kubectl get pv pvc-469ffaff-fa8e-46af-ad10-xxxxxxxxxxx -n rabbitmq -o jsonpath='{.spec.awsElasticBlockStore.volumeID}'
aws://eu-west-1b/vol-00d28xxxxxxxxxxxx

Y creamos un snapshot con AWS CLI o desde la consola web:


:~$ aws ec2 create-snapshot --volume-id vol-00d28xxxxxxxxxxxx --tag-specifications 'ResourceType=snapshot,Tags=[{Key="ec2:ResourceTag/ebs.csi.aws.com/cluster",Value="true"}]'

{
"Description": "",
"Encrypted": false,
"OwnerId": "redacted",
"Progress": "",
"SnapshotId": "snap-89567xxxxxxxxxxx",
"StartTime": "2023-06-23T17:05:49.763000+00:00",
"State": "pending",
"VolumeId": "vol-00d28xxxxxxxxxxxx",
"VolumeSize": 10,
"Tags": [
{
"Key": "ec2:ResourceTag/ebs.csi.aws.com/cluster",
"Value": "true"
}
]
}

Esperamos a que finalice el snapshot para continuar con el siguiente paso.

Paso 2: Asociar snapshot de EBS a recursos de Kubernetes

Creamos el recurso VolumeSnapshotContent con el contenido del snapshot anterior:


:~$ cat volume_snapshot_content.yaml
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshotContent
metadata:
  name: imported-rabbitmq-content
  namespace: rabbitmq
spec:
  volumeSnapshotRef:
    kind: VolumeSnapshot
    name: imported-rabbitmq-snapshot   # <-- objeto no lo hemos creado todavía
    namespace: rabbitmq
  source:
    snapshotHandle: snap-89567xxxxxxxxxxx # <-- snapshot a importar
  driver: ebs.csi.aws.com
  deletionPolicy: Delete
  volumeSnapshotClassName: ebs-csi-aws

:~$ kubectl apply -f volume_snapshot_content.yaml
volumesnapshotcontent.snapshot.storage.k8s.io/imported-rabbitmq-content created

Comprobamos que se ha creado el recurso correctamente en el cluster:


:~$ kubectl get volumesnapshotcontent imported-rabbitmq-content -n rabbitmq
NAME                      READYTOUSE RESTORESIZE   DELETIONPOLICY    DRIVER           VOLUMESNAPSHOTCLASS   VOLUMESNAPSHOT VOLUMESNAPSHOTNAMESPACE      AGE
imported-rabbitmq-content true       10737418240  Delete            ebs.csi.aws.com  ebs-csi-aws           imported-rabbitmq-snapshot   rabbitmq 38s

Asociamos el VolumeSnapshotContent a un nuevo VolumeSnapshot:


:~$ cat volume_snapshot.yaml

apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
  name: imported-rabbitmq-snapshot
  namespace: rabbitmq
spec:
  volumeSnapshotClassName: ebs-csi-aws
  source:
    volumeSnapshotContentName: imported-rabbitmq-content

Paso 3: Crear nuevo PersistentVolumeClaim (PVC) desde VolumeSnapshot

Creamos un nuevo PVC a partir del snapshot creado anteriormente:


:~$ cat new_rabbitmq_pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: imported-rabbitmq-pvc
  namespace: rabbitmq
spec:
  accessModes:
  - ReadWriteOnce
  storageClassName: gp3
  resources:
    requests:
      storage: 10Gi
  dataSource:
    name: imported-rabbitmq-snapshot
    kind: VolumeSnapshot
    apiGroup: snapshot.storage.k8s.io


:~$ kubectl apply -f new_rabbitmq_pvc.yaml
persistentvolumeclaim/imported-rabbitmq-pvc created

Paso 4: Comenzar a utilizar el nuevo PVC

Este paso consiste en cambiar el PVC actual por el nuevo PVC en el servicio que lo utiliza. Los cambios a realizar dependen mucho de a qué recurso esté asociado y cómo lo estés desplegando en tu caso particular. No es lo mismo cambiar un recurso de tipo Statefulsets desplegado a partir de una template con Helm, que editar un manifest “hardcoded” o integrarlo en otros sistemas de automatización de cambios de los recursos del cluster, etc. Debes analizar con atención tu caso de uso concreto.

En nuestro caso de uso del ejemplo, vamos a cambiar el PVC definido en el manifest, y lo cambiamos en configuración actual.
 


:~$ vim rabbitmq-sts.yaml

[....]
  volumeClaimTemplates:
  - metadata:
      name: imported-rabbitmq-pvc
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 10Gi
[...]

:~$ kubectl delete sts rabbitmq -n rabbitmq –cascade=orphan
:~$ kubectl apply -f rabbitmq-sts.yaml

Paso 5: Eliminar antiguo PVC

Si todo ha ido bien, podemos eliminar el PVC anterior (que ya NO estará en estado “Bound”)


:~$ kubectl delete pvc rabbitmq-data-rabbitmq-common-0 -n rabbitmq

Ya podemos gestionar los PV de nuestro cluster directamente creando snapshots vía API de Kubernetes, tanto en su creación como en su borrado.

 

Newsletter de STR Sistemas

Suscríbete a nuestra newsletter para recibir contenido interesante del mundo DevOps y artículos escritos por nuestros técnicos

¡Usamos cookies propias y de terceros para mejorar tu experiencia en esta web! Si sigues navegando, consientes y aceptas estas cookies en tu ordenador, móvil o tablet.

Más información sobre las cookies y cómo cambiar su configuración en tu navegador aquí.

x