Introducción
Los StatefulSets son un recurso potente de Kubernetes para gestionar aplicaciones con estado. Sin embargo, también pueden ser complejos y difíciles de respaldar, lo que puede derivar en pérdida de datos ante una falla.
El año pasado (2022), Google anunció una nueva funcionalidad complementaria para GKE llamada Backup for GKE. Se trata de una forma sencilla y nativa de la nube de proteger, gestionar y restaurar todas las aplicaciones y datos en contenedores.
En este artículo recorreremos los componentes de Backup for GKE y veremos cómo respaldar volúmenes de un StatefulSet de MySQL desplegado en un clúster de GKE.
Arquitectura
Backup for GKE consta de dos componentes principales:
- Un servicio que se ejecuta en Google Cloud y expone una API REST basada en recursos. Este servicio funciona como el plano de control de Backup for GKE e incluye elementos de la consola de Google Cloud que interactúan con esa API.
- Un agente que se ejecuta en cada clúster donde se realizan backups o restauraciones. El agente lleva a cabo las operaciones de backup y restauración en esos clústeres interactuando con la API de Backup for GKE.
El servicio de Backup for GKE se integra con la UI de GKE, la CLI de Google Cloud y APIs REST, ofreciendo flujos de trabajo consistentes para desarrollo y operaciones. En un backup se capturan dos tipos de datos:
- Config backup: un conjunto de manifiestos de recursos de Kubernetes extraídos del API server del clúster que se está respaldando, que captura el estado del clúster.
- Volume backups: un conjunto de respaldos de volúmenes que se corresponden con los recursos
PersistentVolumeClaimpresentes en el config backup.
Puedes elegir qué workloads quieres respaldar o restaurar, o hacerlo con todos. También puedes respaldar workloads de un clúster y restaurarlos en otro, y programar tus backups para que se ejecuten automáticamente, de modo que puedas reaccionar rápido y recuperar tus workloads ante un incidente.
Cómo hacerlo
En los próximos pasos crearemos un clúster zonal de GKE, desplegaremos un MySQL con estado en el clúster y probaremos tanto la creación del backup como la restauración de la base de datos.
Definir las variables
Para simplificar, vamos a crear algunas variables de entorno:
export PROJECT_ID=felipe-playground-378415
export REGION=us-east1
export LOCATION=us-east1-c
export CLUSTER=backup-for-gke
export BK_PLAN_ALL_NAMESPACES=mysql-bk-plan-all-ns
export RESTORE_PLAN_ALL_NAMESPACES=mysql-bk-plan-all-ns
export BK_ALL_NAMESPACES=mysql-bk-all-namespaces
export RESTORE_ALL_NAMESPACES=mysql-restore-all-namespaces
Crear el clúster de GKE
Definamos algunas variables para simplificar los comandos. Acuérdate de poner tu propio PROJECT_ID. Para este ejercicio crearemos un clúster zonal de GKE en la zona us-east1-c. Un clúster zonal tiene un único plano de control en una sola zona. Para workloads de producción, sin embargo, recomiendo usar clústeres regionales, ya que ofrecen mayor disponibilidad al ejecutar varias réplicas del plano de control en distintas zonas dentro de una misma región. Además, estamos usando todos los valores por defecto del clúster: VPC y subredes por defecto, número de nodos, service account por defecto, etc. No recomiendo dejar los valores por defecto en clústeres de producción.
Acuérdate de incluir el flag --addons=BackupRestore en tu comando para que también se desplieguen los controladores de backup y todos los CRDs.
gcloud container clusters create ${CLUSTER} \
--release-channel stable \
--zone ${LOCATION} \
--node-locations ${LOCATION} \
--project ${PROJECT_ID} \
--addons=BackupRestore
Ahora conectémonos al clúster
gcloud container clusters get-credentials ${CLUSTER} \
--zone ${LOCATION} \
--project ${PROJECT_ID}
Instalar un StatefulSet
Ahora vamos a crear nuestro StatefulSet. Para este ejercicio elegí el operador de MySQL, que resulta bastante fácil y directo de instalar con Helm.
helm repo add mysql-operator https://mysql.github.io/mysql-operator/
helm repo update
helm install my-mysql-operator mysql-operator/mysql-operator \
--namespace mysql-operator --create-namespace
Instalar MySQL
Instala MySQL con Helm. ¡No olvides cambiar la contraseña!
helm install mycluster mysql-operator/mysql-innodbcluster \
--set tls.useSelfSigned=true \
--set credentials.root.user=safeuser \
--set credentials.root.password=notsupersafepassword \
--set credentials.root.host="%"
Con el comando kubectl get pods,pvc deberías ver algo similar a esto
NAME READY STATUS RESTARTS AGE
pod/mycluster-0 2/2 Running 0 23m
pod/mycluster-1 2/2 Running 0 23m
pod/mycluster-2 2/2 Running 0 23m
pod/mycluster-router-67585969f6-m9nd7 1/1 Running 0 22m
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
persistentvolumeclaim/datadir-mycluster-0 Bound pvc-d5214172-9b81-4d29-9bf0-9e0dcdc8f691 2Gi RWO standard-rwo 23m
persistentvolumeclaim/datadir-mycluster-1 Bound pvc-df8e188a-51aa-4c4f-acb1-73daa72bc721 2Gi RWO standard-rwo 23m
persistentvolumeclaim/datadir-mycluster-2 Bound pvc-defb5e6e-5946-4183-99d2-c168b05a3d6c 2Gi RWO standard-rwo 23m
¡Perfecto! Como siguiente paso vamos a configurar los recursos de Backup for GKE para nuestro clúster.
Backup for GKE incluye dos tipos de recursos de configuración y control:
BackupPlan: un recurso padre de los recursosBackupque representa una cadena de respaldos. Contiene la configuración del backup, incluyendo el clúster de origen, la selección de qué workloads respaldar y la región donde se almacenan los artefactos deBackupgenerados bajo este plan.RestorePlan: ofrece una plantilla de restauración reutilizable. Contiene la configuración de la restauración, incluyendo el clúster destino donde quieres restaurar el backup, el plan de backup de origen, el alcance de la restauración, el manejo de conflictos y las reglas de sustitución.
Crear un Backup Plan para todos los namespaces
gcloud beta container backup-restore backup-plans create ${BK_PLAN_ALL_NAMESPACES} \
--project=${PROJECT_ID} \
--location=${REGION} \
--cluster=projects/${PROJECT_ID}/locations/${LOCATION}/clusters/${CLUSTER} \
--all-namespaces \
--include-secrets \
--include-volume-data
Crear un Restore Plan para todos los namespaces
gcloud beta container backup-restore restore-plans create ${RESTORE_PLAN_ALL_NAMESPACES}\
--all-namespaces \
--project=${PROJECT_ID} \
--location=${REGION} \
--backup-plan=projects/${PROJECT_ID}/locations/${REGION}/backupPlans/${BK_PLAN_ALL_NAMESPACES} \
--cluster=projects/${PROJECT_ID}/locations/${LOCATION}/clusters/${CLUSTER} \
--cluster-resource-conflict-policy=use-existing-version \
--namespaced-resource-restore-mode=delete-and-restore \
--volume-data-restore-policy=restore-volume-data-from-backup \
--cluster-resource-restore-scope="storage.k8s.io/StorageClass","scheduling.k8s.io/PriorityClass"
Si los comandos anteriores se ejecutaron sin problemas, ya tenemos todos los planes listos.
Crear un backup para todos los namespaces
gcloud beta container backup-restore backups create ${BK_ALL_NAMESPACES} \
--project=${PROJECT_ID} \
--location=${REGION} \
--backup-plan=${BK_PLAN_ALL_NAMESPACES} \
--wait-for-completion
Esto puede tardar un rato según el tamaño de tus volúmenes, pero apenas termine deberías ver el siguiente mensaje.
Backup completed. Backup state: SUCCEEDED
Probar la restauración del backup
gcloud beta container backup-restore restores create ${RESTORE_ALL_NAMESPACES} \
--project=${PROJECT_ID} \
--location=${REGION} \
--restore-plan=${RESTORE_PLAN_ALL_NAMESPACES} \
--backup=projects/$PROJECT_ID/locations/${REGION}/backupPlans/${BK_PLAN_ALL_NAMESPACES}/backups/${BK_ALL_NAMESPACES} \
--wait-for-completion
Restore Completed. Restore stat: SUCCEEDED
¡Y listo, funciona!
Backup for GKE también te permite respaldar un único bundle de aplicación creado mediante el CRD ProtectedApplication, pero eso lo dejamos para otro post.
IaC
A día de hoy (junio/2023) solo contamos con un recurso de Terraform para crear un GKE Backup Plan, llamado google_gke_backup_backup_plan, agregado en la versión 4.5.0 del provider de Google, como puedes ver aquí. Ojalá pronto haya más recursos disponibles.
Precios
Backup for GKE genera cargos en dos dimensiones: por un lado, una tarifa de gestión de backups de GKE basada en el número de pods de GKE protegidos y, por otro, una tarifa de almacenamiento de backups basada en la cantidad de datos (GB) almacenados. Ambas se calculan mensualmente, igual que la facturación de otras funcionalidades de GKE.
Por ejemplo, un cliente con un único backup plan en Iowa (us-central1) que respalda en promedio 20 pods durante un mes y almacena 200 GB de datos de backup en Iowa, pagaría 25,60 USD. Esos 25,60 USD se componen de 20 USD del mes por la gestión de backups de GKE (20 x 1,00 USD / pod-mes) y 5,60 USD por el almacenamiento del backup (200 * 0,028 USD / GB-mes).
A partir del 26 de junio de 2023 se introducirán nuevos cargos de salida de red para los backups que se almacenen en una región distinta a la de su clúster GKE de origen. Estos cargos se calcularán en función de la región de origen y destino y de la cantidad de bytes transferidos en cada operación de backup "cross-region"
Limpieza
Eliminar el clúster
gcloud container clusters delete ${CLUSTER} --project $PROJECT_ID --zone ${LOCATION}
No olvides eliminar también los backups y los planes.
# Eliminar backup
gcloud beta container backup-restore backups delete ${BK_ALL_NAMESPACES} \
--location=${REGION} \
--backup-plan=${BK_PLAN_ALL_NAMESPACES}
# Eliminar backup plan
gcloud beta container backup-restore backup-plans delete ${BK_PLAN_ALL_NAMESPACES} \
--location=${REGION}
# Eliminar restore plan
gcloud beta container backup-restore restore-plans delete ${RESTORE_PLAN_ALL_NAMESPACES} \
--location=${REGION}
¡Espero que disfrutes el recorrido y, si tienes alguna pregunta, no dudes en escribirme!
En resumen, Backup for GKE es una herramienta potente que te ayuda a proteger los datos de tus StatefulSets. Si usas StatefulSets en Kubernetes, vale la pena que consideres Backup for GKE para resguardar tu información.
Recursos: