DEV Community

GERALD DEYBI ZEVALLOS PINTO
GERALD DEYBI ZEVALLOS PINTO

Posted on

Backups en la nube sin dramas

Cómo protegemos SQLite y Oracle en un despliegue automatizado en Azure

1. Introducción: backups, RPO, RTO y qué motores usamos

Un backup que nunca se restauró es una esperanza, no un plan. Antes de tocar un solo comando, conviene fijar dos números:

  • RPO (Recovery Point Objective): cuántos datos estamos dispuestos a perder, medido en tiempo.
  • RTO (Recovery Time Objective): cuánto tiempo podemos tardar en volver a operar.

Nuestro caso de estudio es un Framework de Pruebas SQL hecho con FastAPI. Permite definir casos de prueba, agruparlos en suites, ejecutarlos contra Oracle y guardar un historial de resultados (PASS, FAIL o ERROR). Para dejar claro el alcance: trabajamos con SQLite y Oracle Free, y no usamos MS SQL Server. Este artículo no lo cubre.

SQLite guarda los metadatos de la aplicación: proyectos, perfiles de conexión, casos, suites e historial. Oracle es la base objetivo donde corren las pruebas. Esa diferencia de roles define toda nuestra estrategia.

2. Arquitectura: Azure, contenedores y volúmenes

Todo corre en una máquina virtual de Azure con Docker Compose:

  • Caddy recibe el tráfico y termina HTTPS.
  • Contenedor de la API (framework_api_prod): FastAPI más el frontend. Escribe en SQLite.
  • Contenedor de Oracle Free (framework_oracle_prod): base objetivo de la demostración.
  • Volúmenes persistentes para SQLite y para oracle_data.

Los contenedores son desechables y los volúmenes no. El código y las imágenes se reconstruyen en minutos, pero el historial de ejecuciones solo existe en el volumen. Por eso el volumen es el activo que hay que proteger.

Hay otra decisión de diseño que ayuda. Nuestros perfiles de conexión nunca almacenan la contraseña de Oracle: se pide en el momento de probar o ejecutar. Así, un backup de SQLite no filtra credenciales de bases externas. Sí contiene texto SQL y resultados esperados, así que lo tratamos como información potencialmente sensible y lo cifraríamos en reposo.

3. Backup de SQLite: frío y en caliente

Frío (con la aplicación detenida)

Es el más simple y el más seguro:

bash
docker compose stop api
cp /ruta/volumen/framework.db /backups/framework_$(date -u +%Y%m%dT%H%M%SZ).db
docker compose start api
Enter fullscreen mode Exit fullscreen mode

El costo es una breve interrupción. Es aceptable en una ventana de mantenimiento, no como rutina diaria.

En caliente (con la aplicación en uso)

Un cp sobre una base activa puede producir una copia inconsistente. Si hay modo WAL, copiar solo el .db deja fuera transacciones recientes. Lo correcto es usar la API de backup de SQLite, que genera una copia coherente mientras la app sigue escribiendo. Usamos Python porque ya está en la imagen de la API:

bash
docker exec -i framework_api_prod python - <<'PY'
import sqlite3
src = sqlite3.connect("/app/data/framework.db")      # ruta ilustrativa
dst = sqlite3.connect("/app/data/backups/snapshot.db")
with dst:
    src.backup(dst)
dst.close(); src.close()
PY
Enter fullscreen mode Exit fullscreen mode

Después verificamos y comprimimos la copia antes de subirla:

bash
sqlite3 snapshot.db "PRAGMA integrity_check;"   # debe responder: ok
gzip -9 snapshot.db
Enter fullscreen mode Exit fullscreen mode

Fuera de la VM

Una copia en el mismo disco no sirve si se pierde la VM. La subimos a un almacenamiento separado, por ejemplo Azure Blob Storage con azcopy o az storage blob upload. Un cron o un timer de systemd la programa según el RPO acordado.

Un detalle de honestidad técnica: los snapshots de disco de la VM suelen ser consistentes ante caída, no coherentes a nivel de aplicación. Son un complemento, no un reemplazo del backup lógico.

4. Backup lógico del contenedor de Oracle

Aquí hay un matiz importante. En nuestro despliegue, Oracle Free contiene un esquema de pruebas que se crea con un script de inicialización (001_test_schema.sh). En parte es reproducible, pero si los casos de prueba dependen de datos cargados después, necesitamos un backup lógico con Data Pump:

bash
docker exec framework_oracle_prod bash -c '
  expdp userid="system@//localhost:1521/FREEPDB1" \
        schemas=ESQUEMA_PRUEBAS \
        directory=DATA_PUMP_DIR \
        dumpfile=pruebas_%U.dmp logfile=pruebas_exp.log'
Enter fullscreen mode Exit fullscreen mode

Nombres de esquema y credenciales son ilustrativos. En la práctica usaríamos un parfile con permisos restringidos para no exponer contraseñas en la línea de comandos. El .dmp se copia fuera del contenedor y luego a almacenamiento externo, igual que SQLite. Como alternativa en frío, se detiene el contenedor y se empaqueta el volumen oracle_data.

Una advertencia: Oracle Free no recibe soporte ni parches del fabricante. Para producción real se usa una edición soportada, y la estrategia de backup se rediseña con las herramientas que ese licenciamiento permita.

5. Cómo la automatización acelera la recuperación

Nuestro despliegue se actualiza con GitHub Actions. Como el código y la configuración viven en el repositorio, ante un desastre no hay que reconstruir a mano la aplicación. La receta es: nueva VM (o la misma), pipeline de despliegue y restaurar el volumen de datos.

Un punto fuerte de integrar backups con CI/CD es respaldar antes de cada despliegue, porque ahí se ejecutan las migraciones Alembic sobre SQLite, el momento más riesgoso:

yaml
- name: Backup previo al despliegue
  run: ssh deploy@$VM "/opt/framework/scripts/backup_sqlite.sh"
- name: Desplegar
  run: ssh deploy@$VM "cd /opt/framework && docker compose pull && docker compose up -d"
Enter fullscreen mode Exit fullscreen mode

Este flujo es ilustrativo. Cada equipo lo adapta a sus secretos y rutas.

6. Conclusión

Dos ideas resumen lo aprendido. Primero, separar lo reproducible de lo irremplazable: el código se redespliega, los datos se restauran. Segundo, un backup vale lo que vale su restauración probada. Nuestro siguiente paso es automatizar la copia consistente y ensayar restauraciones periódicas.

🎥 Mira la demostración aquí:

💻 Repositorio: https://github.com/Geraldzvallos/framework-pruebas-sql-publico

Top comments (0)