← Volver al blog

Backup no significa Disaster Recovery

Tener backups no equivale a tener Disaster Recovery: lo que restores reales revelaron sobre control plane, PersistentVolumes, imágenes OCI y recovery offline.

kuberneteshomelabdisaster-recovery

Tenía backups de mi clúster Kubernetes. Entonces hice la pregunta que suele ser fácil posponer: ¿puedo restaurarlos de verdad?

La respuesta corta fue: no tan fácilmente como parecía. El ejercicio dejó de tratar sobre crear backups y pasó a tratar sobre producir un sistema ejecutable en otra máquina.

Dos niveles de recuperación

flowchart LR
    CP[Control plane: SQLite + server token] --> DR[Full DR]
    PV[Persistent volumes] --> DR
    OCI[Imágenes OCI offline] --> DR
    W[Workloads ejecutables] --> DR

Un backup del clúster no es una sola cosa.

El target DR debe ser peligroso por diseño y seguro por control

Usé una segunda máquina Debian 13, guionote-hp, como target de recuperación mientras producción seguía funcionando en guiosoft-info.

flowchart LR
    P[Producción: guiosoft-info] -->|artefactos de backup| D[DR: guionote-hp]
    D --> LAN[LAN + redes Kubernetes]
    D -. bloqueado por nftables .-> WAN((Internet))

El target recibe una barrera WAN independiente con nftables antes del restore. Los scripts destructivos exigen un marker DR, rechazan hostname/IP de producción y requieren confirmación explícita. El reset también ganó un preflight no destructivo; al probarlo deliberadamente contra producción, rechazó la ejecución antes de cualquier cambio.

Primer problema: el datastore no vive solo

Restaurar únicamente base de datos y token manteniendo material TLS/credentials del target limpio podía producir incompatibilidades de bootstrap. La estrategia cambió: preservar el material del target en una zona segura, restaurar el datastore y permitir que K3s reconstruya el bootstrap desde el estado recuperado.

Segundo problema: los PersistentVolumes locales recuerdan el servidor anterior

Los PVs recuperados seguían teniendo node affinity para producción y paths locales del storage de producción. Esos campos no pueden corregirse simplemente con un patch normal.

flowchart TD
    Q[Writers recuperados en 0] --> R[Reclaim policy Retain]
    R --> M[Preservar manifests]
    M --> D[Eliminar objetos PVC/PV antiguos de forma segura]
    D --> P[Recrear PVs con path DR + affinity al node futuro]
    P --> C[Recrear PVCs pre-bound por volumeName]
    C --> V[Verificar nuevos UIDs, claimRefs y Bound]
    V --> A[Activar node y workloads]

Pods recuperados en Terminating también podían mantener referencias a PVCs protegidos, así que solo se eliminaron los Pods que bloqueaban la transacción.

Tercer problema: el clúster restaurado empieza sin el node DR

Durante el restore aislado, K3s arranca agentless (disable-agent:true). El Node DR todavía no existe. Por eso el remapeo de PV debe aceptar affinity para un hostname futuro.

Cuarto problema: una imagen listada no es necesariamente un backup

El content store de containerd en producción no era un backup de imágenes fiable. La solución fue un kit OCI linux/amd64 con checksums generados en origen, cargado mediante el directorio nativo de preload de K3s:

/var/lib/rancher/k3s/agent/images/

La validación se realiza por CRI, manteniendo el recovery independiente de registries externos.

GitHub también desaparece durante el desastre

Si DR bloquea Internet, el runbook no puede depender de git pull.

flowchart LR
    Git[Git como fuente de verdad] --> Normal[Operación normal]
    Kit[Kit de recovery offline] --> DR[DR aislado]
    Key[Backup independiente de clave privada] --> DR

El kit lleva scripts, checksums, imágenes OCI y material cifrado. Las credenciales privadas siguen fuera de Git y tienen recuperación independiente.

¿Y los workloads?

Grafana, Loki, Prometheus y Tempo fueron recuperados. En un rehearsal, Tempo descartó un bloque WAL incompleto sin meta.json, una señal de que una copia de filesystem puede ser recuperable sin ser consistente a nivel de aplicación.

El principal aprendizaje

Suposición Lo que mostró el rehearsal
Backup del datastore No equivale a un clúster ejecutable
Datos del PV No son automáticamente utilizables en otro node
Imagen en containerd No es necesariamente un backup OCI fiable
Git disponible hoy No garantiza Git durante DR
Script terminó con 0 No prueba la postcondición

Backup es un artefacto. Disaster Recovery es una capacidad que debe ejercitarse.

Después de conseguir recuperar el entorno apareció la siguiente pregunta: ¿cuánto tiempo tarda? Ese es el tema del próximo artículo.


Proyecto: guionardo/guiosoft-k3s-lab.