Autor: Yerry Maycol Tarqui Collatupa
Trabajo: NoSQL Backup Strategy
En este artículo se documentan el diseño, la automatización y la validación de una estrategia de respaldo y recuperación para una aplicación con Azure Cosmos DB, una base de datos NoSQL, con respaldos cifrados en Azure Blob Storage y flujos de GitHub Actions.
Introducción
Contar con una base de datos en la nube no elimina el riesgo de perder información: un borrado accidental, un error de la aplicación o una operación equivocada pueden destruir datos que ningún servicio recupera por sí solo. Por eso una estrategia de respaldo no se limita a generar copias; también debe definir dónde se guardan, cómo se protegen, cuánto tiempo se conservan y, sobre todo, cómo se comprueba que pueden restaurarse.
A partir de ese problema se desarrolló NoSQL Backup Strategy, un proyecto práctico que construye una aplicación de productos con ASP.NET Core y Azure Cosmos DB, y una herramienta propia, BackupTool, que genera respaldos cifrados de la base y los restaura con verificación. El proyecto integra Terraform para describir la infraestructura como código, GitHub Actions para automatizar el despliegue, el respaldo diario y la recuperación, Azure Blob Storage para conservar las copias y Azure App Service para publicar la aplicación en una nube pública.
La implementación se realizó de forma progresiva. Primero se construyeron la aplicación y la herramienta de respaldo; después se definió la infraestructura y se automatizó su creación y el despliegue. Con la aplicación publicada se generó un respaldo, se simuló un desastre que eliminó todos los datos y se restauraron desde la copia cifrada. Esta publicación documenta las evidencias principales del trabajo.
Estrategia de respaldo
La estrategia combina tres capas complementarias. La primera es el respaldo nativo de Cosmos DB, con política Periodic cada 240 minutos y retención de 48 horas, definida en Terraform. La segunda es un respaldo lógico propio: BackupTool lee todos los documentos, los empaqueta en un archivo JSON con un manifiesto (fecha, base, contenedor y cantidad), calcula el SHA-256 de los datos, los comprime con GZip y los cifra con AES-256-GCM, con una clave derivada con PBKDF2. El archivo resultante se guarda en un contenedor privado de Blob Storage. La tercera es la retención automática: una política de ciclo de vida elimina los respaldos con más de 30 días.
La recuperación sigue el camino inverso: descarga el respaldo, lo descifra, restaura los documentos en el contenedor indicado y verifica que la cantidad restaurada coincida con la del manifiesto. Si no coincide, el proceso termina con error.
Arquitectura de la solución
La aplicación es una página web con una API REST alojada en Azure App Service, que usa Azure Cosmos DB en modo serverless con la API NoSQL. Los respaldos no dependen de la aplicación: los flujos de GitHub Actions ejecutan BackupTool, que lee la base, cifra los datos y los sube a Blob Storage, y que también los restaura cuando se necesita.
Figura 1. Arquitectura de la solución: aplicación en App Service, Cosmos DB, BackupTool ejecutado por GitHub Actions y respaldos cifrados en Blob Storage.
Creación de los proyectos
La solución tiene dos proyectos .NET dentro del mismo repositorio. El primero, ProductosApi, es la aplicación web creada con la plantilla web mínima de ASP.NET Core.
Figura 2. Creación del proyecto ProductosApi con la plantilla web mínima de ASP.NET Core.
El segundo, BackupTool, es una aplicación de consola. A este proyecto se agregaron los paquetes Microsoft.Azure.Cosmos y Newtonsoft.Json, necesarios para leer Cosmos DB, y Azure.Storage.Blobs, para escribir en Blob Storage.
Figura 3. Paquetes instalados en el proyecto BackupTool.
Código de la solución
En Program.cs de la API se configuró el cliente de Cosmos DB con la configuración de la aplicación, se creó la base y el contenedor si no existen y se definieron los endpoints: /health para comprobar el estado y /api/productos para listar, consultar, crear, actualizar y eliminar productos, además de un endpoint que carga productos de ejemplo. La llave de acceso no se escribe en el código, sino que se entrega como configuración.
Figura 4. Endpoints de la API definidos en Program.cs.
El acceso a los datos se encapsuló en la clase ProductosRepo, que concentra las consultas SQL de Cosmos DB y las operaciones de lectura, creación, reemplazo, eliminación y conteo de documentos.
Figura 5. Clase ProductosRepo para el acceso al contenedor de Cosmos DB.
BackupTool implementa los comandos backup, restore, listar y destruir. El respaldo consulta todos los documentos, arma el manifiesto, calcula el SHA-256, comprime, cifra con AES-GCM y sube el archivo al contenedor backups con su cantidad y su huella como metadatos.
Figura 6. Generación del respaldo cifrado en BackupTool.
La restauración descarga el respaldo indicado o el más reciente, lo descifra, lo escribe en el contenedor de destino y verifica la cantidad de documentos. El comando listar muestra los respaldos almacenados, y destruir, que exige el parámetro de confirmación, permite simular un desastre.
Figura 7. Restauración con verificación, listado de respaldos y comando de destrucción.
Infraestructura como código
La infraestructura se describió con Terraform en el archivo main.tf: la cuenta de Cosmos DB serverless con la política de respaldo Periodic, la base productosdb y el contenedor productos, la cuenta de Storage con el contenedor privado backups y su política de retención de 30 días, el plan de App Service gratuito (F1) y la aplicación web con .NET 10. El estado de Terraform se guarda en una cuenta de Azure Storage.
Figura 8. Recursos de Azure definidos con Terraform en main.tf.
Automatización con GitHub Actions
El flujo backup.yml genera el respaldo. Inicia sesión en Azure, obtiene las conexiones de Cosmos DB y de Storage y enmascara los secretos en los registros, compila BackupTool, genera el respaldo cifrado y lista los respaldos almacenados. La frase de cifrado es un secreto del repositorio.
Figura 9. Flujo backup.yml que genera el respaldo cifrado.
Este flujo se ejecuta de forma automática todos los días. En el bloque schedule se define la expresión cron 17 10 * * *, que lo programa a las 10:17 UTC (5:17 a. m. en Perú), sin intervención manual; además se mantiene workflow_dispatch para poder lanzarlo a demanda y realizar pruebas.
Figura 10. Bloque schedule con la expresión cron y el disparador workflow_dispatch en backup.yml.
Para la recuperación se creó restore.yml, que recibe el nombre del respaldo (o el último) y el contenedor de destino, restaura los datos y verifica el resultado. Como complemento, desastre.yml elimina todos los productos solo si se escribe la confirmación BORRAR, y sirve para demostrar la recuperación.
Figura 11. Flujo restore.yml que restaura y verifica los datos.
Creación de la infraestructura y despliegue
La infraestructura se creó ejecutando el flujo infra.yml desde la CLI de GitHub, y Terraform creó los recursos de Azure.
Figura 12. Ejecución del flujo infra.yml que crea la infraestructura.
Con la infraestructura lista se ejecutó deploy.yml, que compila y publica la aplicación, la despliega en App Service y comprueba el endpoint /health.
Figura 13. Ejecución del flujo deploy.yml que publica la aplicación.
Aplicación publicada
La aplicación quedó disponible en una URL pública de Azure App Service. Al ingresar se comprobó que se conectaba a Cosmos DB y que aún no tenía productos.
Figura 14. Aplicación publicada en Azure, sin productos.
El botón de ejemplos cargó cinco productos, que se guardaron como documentos en Cosmos DB.
Figura 15. Productos de ejemplo cargados desde la aplicación publicada.
Se agregó un producto más desde el formulario, con lo que la base quedó con seis documentos.
Figura 16. Seis productos guardados en Cosmos DB.
Respaldo
Para comprobar el flujo sin esperar a la ejecución programada de las 10:17 UTC, se lanzó backup.yml de forma manual. El flujo terminó con estado exitoso en menos de un minuto.
Figura 17. Flujo backup.yml finalizado correctamente.
El registro del paso que genera el respaldo muestra los seis documentos respaldados, el nombre del archivo cifrado, su tamaño, el SHA-256 de los datos y el mensaje BACKUP OK.
Figura 18. Seis documentos respaldados y archivo cifrado generado.
En el portal de Azure se comprobó que el archivo cifrado está en el contenedor privado backups de la cuenta de almacenamiento.
Figura 19. Respaldo cifrado almacenado en el contenedor privado de Blob Storage.
Simulación de desastre
Para demostrar la recuperación se lanzó desastre.yml con la confirmación BORRAR, que eliminó todos los productos de la base de datos.
Figura 20. Flujo desastre.yml que elimina los productos.
Al actualizar la aplicación publicada se comprobó que ya no tenía productos: el pie de página indica cero productos guardados.
Figura 21. Aplicación sin datos tras la simulación de desastre.
Recuperación
Se lanzó restore.yml con el último respaldo y como destino el contenedor productos, el que usa la aplicación. El flujo terminó con estado exitoso en 45 segundos.
Figura 22. Flujo restore.yml finalizado correctamente.
El registro muestra el respaldo utilizado, su fecha, el mismo SHA-256 del respaldo original, los seis documentos restaurados y el mensaje VERIFICACION OK.
Figura 23. Restauración verificada: seis documentos recuperados.
Al actualizar la aplicación, los seis productos volvieron a aparecer, con lo que se comprobó que la estrategia permite recuperar los datos después de un desastre.
Figura 24. Productos recuperados desde el respaldo cifrado.
Repositorio público
Todo el trabajo está en un repositorio público de GitHub que contiene el código de la aplicación y de BackupTool, la infraestructura de Terraform, los flujos de GitHub Actions y las capturas del proceso. Las llaves de acceso y la frase de cifrado no forman parte del repositorio.
Figura 25. Repositorio público con el flujo de integración en verde.
Figura 26. Ejecuciones de los flujos de infraestructura, despliegue, respaldo, desastre y restauración.
Resultados
La implementación permitió comprobar un ciclo completo de protección y recuperación de datos: se respaldaron seis documentos, se eliminaron todos los productos y se restauraron desde el último respaldo cifrado, con verificación de la cantidad y del SHA-256 de los datos. Toda la solución se crea y se opera desde el repositorio: la infraestructura con Terraform, la aplicación con un flujo de despliegue y los procedimientos de respaldo y recuperación con flujos que pueden ejecutarse en cualquier momento.
| Componente | Validación | Resultado |
|---|---|---|
| Aplicación ASP.NET Core | Publicada en App Service y conectada a Cosmos DB | Seis productos guardados |
| Respaldo cifrado | backup.yml y BackupTool | Seis documentos respaldados |
| Blob Storage | Contenedor privado backups | Archivo cifrado almacenado |
| Programación | cron 17 10 * * * (diario, 10:17 UTC) | Configurada |
| Desastre | desastre.yml con confirmación BORRAR | Cero productos |
| Restauración | restore.yml con el último respaldo | VERIFICACION OK |
| Aplicación recuperada | Consulta de la aplicación publicada | Seis productos |
| Repositorio público | Código, infraestructura y flujos | Publicado |
Conclusiones
Un respaldo es útil solo si se puede restaurar: por eso cada recuperación verifica la cantidad de documentos y el SHA-256 de los datos.
Cifrar el respaldo antes de subirlo protege los datos aunque alguien acceda al contenedor de Blob Storage, y la política de ciclo de vida evita acumular archivos antiguos.
Combinar el respaldo nativo de Cosmos DB con un respaldo lógico propio da dos vías de recuperación: una administrada por la plataforma y otra bajo control del equipo, que además puede restaurarse en otro contenedor.
GitHub Actions automatizó el respaldo diario, el despliegue y los procedimientos de recuperación, lo que reduce los pasos manuales y los errores.
La combinación de Cosmos DB serverless, el plan F1 de App Service y un almacenamiento pequeño permitió publicar la solución en una nube pública con un costo mínimo.
Enlaces del proyecto
Repositorio público: tg2-nosql-backup-yerrytc en GitHub
Aplicación publicada: Abrir la aplicación en Azure
Nota: La aplicación está desplegada en el plan gratuito F1 de Azure App Service, por lo que puede tardar hasta un minuto en responder después de un periodo de inactividad. Una vez iniciada, funciona con normalidad.
Video de demostración: Ver en YouTube (4 min 32 s)
![Robot Hand and Dexterous Grasping — Ch.15: Case Studies [EN]](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2atidcc9udjuab3sdlx3.png)
![Differential Drive, Steer Drive and Omni Drive — Ch.23: Steer Drive Power and Electrical System [KR]](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3snk5qxp01873zhshtp9.png)
![Differential Drive, Steer Drive and Omni Drive — Ch.26: Engineering Checklists [KR]](https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fod0jcp4wdocjb8jg7gps.png)