Autor: Yerry Maycol Tarqui Collatupa
Curso: Base de Datos II — Universidad Privada de Tacna
Trabajo: Database Backup Strategies
En este artículo documentamos la construcción, automatización y validación de estrategias de respaldo y recuperación de PostgreSQL, desde un entorno local con Docker hasta Render y GitHub Actions.
Introducción
La pérdida de información puede comprometer la continuidad de una aplicación incluso cuando el código fuente se encuentra correctamente versionado. En un sistema que depende de una base de datos, disponer de una copia de seguridad no es suficiente por sí solo: también es necesario comprobar que el archivo generado puede restaurarse, definir dónde se conservará y reducir la cantidad de tareas manuales necesarias para producir nuevas copias.
A partir de este problema desarrollamos Database Backup Strategies, un proyecto práctico orientado a implementar y validar estrategias de respaldo y recuperación de PostgreSQL. El trabajo integra Docker y Docker Compose para el entorno local, PowerShell para la generación de copias, FastAPI para exponer los datos, GitHub para el control de versiones, Render para el despliegue en la nube y GitHub Actions para automatizar respaldos remotos cifrados.
La implementación se construyó de forma progresiva. Primero preparamos PostgreSQL y datos de prueba; después generamos respaldos locales, automatizamos su ejecución y demostramos su recuperación. Sobre esa base publicamos una API en Render, verificamos el despliegue automático desde GitHub y finalmente automatizamos también el respaldo de PostgreSQL en la nube. Esta publicación documenta las evidencias principales del trabajo sin convertir el artículo en una simple sucesión de capturas.
Arquitectura de la solución
La solución se diseñó con dos entornos complementarios. En local, Docker Compose ejecuta PostgreSQL y FastAPI; PowerShell invoca pg_dump y el Programador de tareas de Windows permite programar las copias. En la nube, Render aloja PostgreSQL y la API, mientras que GitHub mantiene el código y activa el despliegue del servicio cuando se actualiza la rama principal.
Figura 1. Flujo de respaldo automático de PostgreSQL en Render mediante GitHub Actions y almacenamiento privado.
Para separar el código de las copias de seguridad utilizamos dos repositorios. El proyecto principal es público y contiene únicamente los archivos necesarios para reproducir la aplicación. Los respaldos remotos, en cambio, se conservan cifrados en un repositorio privado independiente. De esta manera, la solución diferencia con claridad el código fuente, la infraestructura de ejecución y los archivos de recuperación.
Preparación del entorno local
Comenzamos verificando Docker y Docker Compose en el equipo de desarrollo. Esta comprobación permitió asegurar que el entorno podía crear contenedores, construir imágenes y administrar los servicios requeridos para PostgreSQL y la aplicación web.
Figura 2. Comprobación del entorno de Docker antes de iniciar la implementación.
PostgreSQL se configuró con Docker Compose sobre una imagen de la versión 16. Las credenciales y el nombre de la base se definieron mediante variables de entorno, mientras que un volumen persistente se encargó de conservar los datos del motor fuera del ciclo de vida del contenedor. Las credenciales reales se mantuvieron excluidas del repositorio mediante .gitignore.
Con el servicio activo comprobamos la conexión y ejecutamos un script SQL para crear la tabla productos. Como conjunto de validación insertamos tres registros claramente identificables: Laptop Lenovo, Mouse Logitech y Teclado mecánico. Estos mismos registros se utilizaron posteriormente para comprobar tanto la API como las restauraciones.
Figura 3. Datos de prueba almacenados en la tabla productos de PostgreSQL.
Generación del backup local
El primer mecanismo de respaldo se implementó mediante un script PowerShell denominado backup.ps1. El script genera un nombre de archivo basado en fecha y hora, ejecuta pg_dump dentro del contenedor, copia el resultado a la carpeta local backups y comprueba que el archivo resultante tenga contenido. Esta verificación evita considerar como válido un archivo vacío o una ejecución interrumpida.
Figura 4. Script PowerShell utilizado para generar el respaldo local con pg_dump.
Antes de automatizar el proceso ejecutamos el script manualmente. La prueba generó correctamente un archivo en formato personalizado de PostgreSQL, lo que confirmó que las variables, el contenedor y la ruta de almacenamiento estaban configurados de manera coherente.
Figura 5. Primera ejecución satisfactoria del backup local.
Automatización local
Una vez validado el script configuramos el Programador de tareas de Windows para ejecutarlo sin intervención manual. Durante la prueba se estableció una repetición cada cinco minutos durante una hora. Este intervalo corto se utilizó únicamente para demostrar varias ejecuciones dentro del tiempo de validación; en un escenario productivo la frecuencia debe definirse de acuerdo con las necesidades de recuperación del sistema.
Figura 6. Desencadenador configurado para repetir el backup cada cinco minutos durante la prueba.
El resultado se comprobó observando el historial de la tarea y la creación sucesiva de archivos .dump con marcas de tiempo diferentes. Con ello demostramos que el respaldo local no dependía de ejecutar manualmente backup.ps1 en cada ocasión.
Figura 7. Ejecución programada y aparición sucesiva de respaldos locales.
Restauración y validación
La generación de una copia no se dio por válida hasta comprobar su recuperación. Seleccionamos el respaldo más reciente, lo copiamos al contenedor y utilizamos pg_restore para inspeccionar su contenido. La lista mostró los objetos asociados a la tabla productos, incluidas su secuencia, restricciones y datos.
Figura 8. Inspección del contenido del respaldo mediante pg_restore.
Posteriormente creamos una base de datos independiente destinada únicamente a la restauración. Ejecutamos pg_restore sobre ella y consultamos nuevamente productos. Los tres registros originales aparecieron con sus valores de precio y stock, confirmando que la copia podía utilizarse para recuperar la información sin alterar la base de datos principal.
Figura 9. Restauración local completada y recuperación de los tres productos.
Aplicación FastAPI
Para disponer de una comprobación funcional sobre los datos construimos una API REST con FastAPI. La aplicación obtiene la cadena de conexión desde DATABASE_URL y expone tres rutas principales: la raíz para informar el estado de la aplicación, /health para validar PostgreSQL y /productos para consultar los registros almacenados.
Figura 10. Implementación de los endpoints principales de FastAPI.
La API se incorporó a Docker Compose y se ejecutó junto con PostgreSQL. Finalmente utilizamos la documentación Swagger de FastAPI para invocar GET /productos. La respuesta HTTP 200 mostró exactamente los mismos tres registros utilizados en las pruebas de restauración.
Figura 11. Respuesta HTTP 200 de GET /productos desde Swagger.
Repositorio público
Antes de publicar el proyecto protegimos los archivos sensibles. El archivo .gitignore excluyó variables de entorno, copias .dump, evidencias locales y otros archivos que no debían formar parte del repositorio. Para facilitar la configuración posterior se mantuvo una plantilla .env.example sin utilizar el archivo .env real.
Figura 12. Reglas de exclusión empleadas antes de publicar el proyecto.
Después inicializamos Git, realizamos el primer commit y creamos un repositorio público. El resultado deja disponibles el código de FastAPI, Dockerfile, Docker Compose, el script SQL y backup.ps1, manteniendo fuera de Git las credenciales y los respaldos generados.
Figura 13. Repositorio público del proyecto Database Backup Strategies.
Publicación en la nube
El siguiente objetivo fue ejecutar la solución fuera del equipo local. Creamos el proyecto en Render y posteriormente una instancia de PostgreSQL asociada al entorno de producción. La base quedó disponible y preparada para ser utilizada por el servicio web.
Figura 14. Configuración de recursos para la instancia PostgreSQL en Render.
FastAPI se desplegó como Web Service conectado al repositorio de GitHub. La configuración utilizó Docker y la variable DATABASE_URL para enlazar la aplicación con PostgreSQL en Render. Una vez finalizado el despliegue, el servicio quedó accesible mediante una URL pública.
Figura 15. Despliegue inicial de FastAPI completado correctamente en Render.
Después cargamos los datos de prueba en la base remota y repetimos las verificaciones realizadas en local. El endpoint público /productos devolvió los tres registros, demostrando que la aplicación estaba utilizando PostgreSQL en Render y no la base local.
Figura 16. Consulta pública de /productos utilizando PostgreSQL alojado en Render.
Despliegue automatizado
Para demostrar el despliegue automatizado verificamos que Render estuviera configurado para actualizar el servicio a partir de cambios en la rama principal del repositorio. Modificamos el endpoint inicial de FastAPI para incorporar la versión 1.0.1 y el texto que identifica el despliegue desde GitHub.
El cambio se registró mediante commit y se envió con git push a main. A partir de ese envío, Render detectó la nueva revisión y generó un nuevo despliegue sin que tuviéramos que reconstruir manualmente el servicio desde el panel.
Figura 17. Registro del despliegue automático en Render activado desde GitHub.
Al finalizar, la URL pública mostró la versión 1.0.1 y el indicador de despliegue automatizado. Esta prueba permitió diferenciar claramente el despliegue automático de la automatización de backups: el primero publica nuevas versiones de la aplicación y el segundo genera copias de la base de datos.
Figura 18. Versión 1.0.1 publicada automáticamente en Render después del push.
Backup de PostgreSQL de Render
Con la aplicación ya publicada comprobamos también la recuperación de los datos de la nube. Para ello utilizamos temporalmente la External Database URL de Render sin exponerla en las capturas. Mediante pg_dump generamos una copia completa de PostgreSQL remoto en formato personalizado y verificamos su contenido con pg_restore.
Figura 19. Generación e inspección del backup de PostgreSQL alojado en Render.
El archivo se copió desde el contenedor hacia Windows con un nombre que incorpora fecha y hora. Después lo introdujimos nuevamente en el contenedor y lo restauramos sobre una base de datos local de prueba. La ejecución terminó con código 0 y la consulta final recuperó Laptop Lenovo, Mouse Logitech y Teclado mecánico.
Figura 20. Restauración del backup de Render y validación de los tres productos recuperados.
Backup automático en la nube
La prueba anterior demostraba que la base remota podía respaldarse, pero todavía dependía de una ejecución manual. Para convertirla en un proceso automático creamos un segundo repositorio privado destinado exclusivamente a almacenar las copias cifradas. De esta forma, los respaldos quedan separados del repositorio público de código.
Figura 21. Repositorio privado creado para almacenar los respaldos de PostgreSQL.
La URL de PostgreSQL y la frase utilizada para cifrar los archivos se configuraron como Repository Secrets. En el repositorio únicamente se muestran los nombres RENDER_DATABASE_URL y BACKUP_PASSPHRASE; sus valores no aparecen en el workflow ni en las evidencias.
Figura 22. Secretos de GitHub Actions utilizados por el proceso de backup.
El workflow backup-render.yml automatiza cuatro operaciones: conecta con PostgreSQL en Render, genera el dump mediante pg_dump, comprueba que el respaldo incluya los datos esperados y cifra el archivo antes de guardarlo. La programación diaria se definió mediante cron y se mantuvo workflow_dispatch para poder realizar pruebas manuales.
Figura 23. Workflow de GitHub Actions encargado de generar, validar y cifrar los respaldos.
Programación del workflow:
on:
schedule:
- cron: '17 10 * * *'
workflow_dispatch:
La expresión cron se configuró para una ejecución diaria con objetivo de las 10:17 UTC, equivalente a las 5:17 a. m. en Perú. Para la demostración también se habilitó la ejecución manual del mismo workflow.
Validación de la automatización
La primera validación se realizó mediante Run workflow para comprobar inmediatamente que la conexión, el cifrado y el commit del respaldo funcionaran. La ejecución terminó correctamente y creó el primer archivo con extensión .dump.enc en la carpeta backups del repositorio privado.
Figura 24. Primer respaldo cifrado creado por GitHub Actions.
Después dejamos activa la programación y revisamos el historial de Actions. Allí apareció una segunda ejecución identificada como Scheduled, diferenciada de la prueba manual. Ambas finalizaron con estado satisfactorio, lo que confirmó que el proceso podía iniciarse sin intervención del usuario.
Figura 25. Historial con una ejecución manual y una ejecución programada (Scheduled).
La carpeta backups mostró dos archivos cifrados con marcas de tiempo distintas. Esta evidencia final confirmó que la base de Render dispone de un mecanismo periódico de respaldo externo que no requiere mantener encendida la computadora de desarrollo.
Figura 26. Respaldos cifrados generados en momentos diferentes dentro del repositorio privado.
Resultados
La implementación permitió comprobar un ciclo completo de protección y recuperación de datos. En local se generaron respaldos mediante pg_dump, se automatizaron con Windows y se restauraron en una base independiente. La recuperación de los tres productos confirmó que los archivos obtenidos eran utilizables y no simples evidencias de ejecución.
La API FastAPI permitió utilizar los mismos datos desde una interfaz web y posteriormente trasladar la solución a Render. El repositorio público quedó separado de las credenciales; Render desplegó la aplicación y PostgreSQL; el cambio a la versión 1.0.1 comprobó el despliegue automático desde GitHub. Finalmente, GitHub Actions automatizó también los respaldos de la base remota, cifrándolos y almacenándolos fuera del entorno de producción.
| Componente | Validación | Resultado |
|---|---|---|
| Backup local | pg_dump ejecutado desde PowerShell | Completado |
| Automatización local | Programador de tareas cada 5 min durante la prueba | Verificada |
| Restauración local | pg_restore en base independiente | 3 productos recuperados |
| FastAPI | /, /health, /productos y /docs | HTTP 200 / conexión correcta |
| Repositorio público | Código sin .env ni backups locales | Publicado |
| Render | PostgreSQL + FastAPI | Desplegados |
| Despliegue automático | Push a main → versión 1.0.1 | Verificado |
| Backup de Render | Dump remoto + restauración local | Verificado |
| GitHub Actions | Manual + Scheduled | Backups cifrados generados |
Conclusiones
La validez de una estrategia de backup debe demostrarse mediante restauraciones reales. En este proyecto los respaldos locales y el respaldo de Render fueron recuperados sobre bases independientes y conservaron los tres registros de prueba.
Docker y Docker Compose permitieron reproducir PostgreSQL y FastAPI de manera consistente, mientras que las variables de entorno evitaron acoplar la aplicación a una única instalación.
La automatización local con PowerShell y el Programador de tareas redujo la intervención manual en el equipo de desarrollo, y GitHub Actions extendió esa automatización a PostgreSQL en la nube sin depender de mantener una computadora encendida.
El despliegue automático desde GitHub hacia Render permitió publicar una nueva versión de FastAPI a partir de un push a la rama principal, demostrando un flujo de actualización diferente e independiente del mecanismo de backup.
El cifrado y almacenamiento de los respaldos remotos en un repositorio privado separan las copias de recuperación del entorno productivo y del repositorio público de código, fortaleciendo la organización y protección de la solución.
Enlaces del proyecto
Repositorio público: Database Backup Strategies en GitHub
API pública (Swagger): Probar endpoints en Render
Nota: La API está desplegada en el plan gratuito de Render, por lo que puede tardar unos minutos en activarse después de un periodo de inactividad. Una vez iniciada, se mostrará la documentación interactiva de Swagger.Video de demostración: Ver en YouTube (4 min 48 s)
Top comments (0)