No sabría entender este trabajo sin la investigación. Tras tres años en el CERN, al volver a Bilbao decidí trabajar por mi cuenta y seguir investigando y aprendiendo. Creo que emprender es el reto profesional definitivo, y a la vez una expresión de creatividad y un reclamo de libertad.
Zetesis viene del griego ζήτησις, indagación: buscar la causa antes de proponer la solución.
Qué datos merece la pena copiar y en qué orden se restauran lo expliqué en Montar un homelab desde cero: backups y restauración, y aquí no lo repito. Como en los anteriores, no doy nombres de máquinas, direcciones ni dominios.
Cada máquina hace su copia con restic
Las copias de ficheros las hace restic, un programa de copias de seguridad que guarda los datos en un repositorio: una carpeta, o un bucket de un almacenamiento compatible con S3, con los datos troceados y cifrados. Cada carga tiene su propio repositorio, así que las copias de producción no se mezclan con las de un VPS.
Lo que cambia de una máquina a otra es quién lanza restic. En el cluster de producción lo hace K8up, un operador de Kubernetes: cada namespace declara en un recurso Schedule qué volúmenes copia, a qué repositorio y a qué hora, y K8up arranca un pod con restic cuando toca. En el de plataforma lo hace VolSync, otro operador, que antes de copiar hace un snapshot ZFS del volumen y lo clona en uno temporal. Restic lee ese clon, una foto quieta del disco, en vez de un volumen que se está escribiendo.
En los VPS no hay Kubernetes. Allí restic va en un contenedor junto a los servicios, con sus volúmenes montados en solo lectura, y se programa solo. Casi todo se copia de madrugada.
Restic cifra y deduplica antes de que salga nada
Antes de enviar nada, restic corta cada fichero en trozos según su contenido y calcula una huella de cada trozo. Si un trozo ya está en el repositorio, no lo vuelve a subir: un fichero que no ha cambiado desde ayer no viaja, y dos ficheros iguales ocupan lo que uno. Después cifra cada trozo con la clave del repositorio.
Al almacenamiento solo llegan trozos cifrados: sin la contraseña, un repositorio de restic no se puede leer. Y la copia de cada noche ocupa poco más que lo que ha cambiado ese día.
PostgreSQL va aparte
Las bases de datos de los clusters tienen su propio camino, con herramientas que entienden PostgreSQL. Las gestiona CloudNativePG, el operador que corre PostgreSQL dentro de Kubernetes, y su plugin de Barman guarda en MinIO dos cosas: el archivo continuo del WAL, el registro donde PostgreSQL anota cada cambio, y una copia base cada día. Juntas permiten recuperar una base hasta un instante concreto, y se conservan 30 días.
Además, cada noche K8up arranca un pod que vuelca las bases principales con pg_dump antes de la copia del namespace de datos, y restic guarda ese volcado en su repositorio como un fichero más. Es una segunda copia en otro formato, que se puede restaurar en cualquier PostgreSQL.
Cada domingo, una prueba restaura cada base
Una copia que nunca se ha restaurado es una hipótesis. Para PostgreSQL tengo una prueba semanal: un CronJob, una tarea programada de Kubernetes, que los domingos a primera hora recorre las bases del cluster de producción. Para cada una crea una base vacía con un prefijo propio, vuelca en ella la original con pg_dump y pg_restore, comprueba que trae tablas y la borra. Si una falla, la prueba sigue con las demás y termina en error, con lo que salta una alerta.
La prueba parte de la base en marcha, no de la copia guardada en MinIO. Lo que comprueba es que cada base se puede volcar y reconstruir entera, sin objetos corruptos ni permisos que lo impidan. Se salta las bases de más de 2 GB, porque la copia desechable ocupa lo mismo que la original, y deja escrito cuáles ha saltado, para no confundir «no ha fallado» con «lo ha comprobado todo».
Las copias viajan por Tailscale hasta un solo puerto
Todas las copias, las de restic y las de PostgreSQL, van al mismo sitio: MinIO, un almacenamiento de objetos compatible con S3 que corre en el TrueNAS de la otra casa. Viajan por Tailscale, la red privada entre máquinas que expliqué en el post de la red. Los clusters salen por un egress de Tailscale, un proxy que el operador de Tailscale levanta dentro del cluster para llevar el tráfico de un servicio interno hasta el NAS. Los VPS usan su propia conexión a Tailscale o un contenedor pasarela que comparte red con el de restic.
La política de Tailscale deja a los cuatro VPS y a los dos clusters llegar al NAS por un único puerto, el de MinIO. En la tabla de accesos del post de la red es la fila del almacenamiento de las copias, la del puerto «uno solo».
Un disco de 16 TB en la otra casa y otro en la principal
MinIO guarda los repositorios en un disco de 16 TB del TrueNAS. Que esté en la otra casa es lo importante: un incendio o un robo en la casa principal se llevaría los servidores, pero no sus copias.
De vez en cuando copio a mano la raíz de ficheros del TrueNAS a otro disco de 16 TB que tengo en la casa principal, con FreeFileSync, un programa que compara dos carpetas y copia las diferencias. Así, si cae una casa, una copia sigue en la otra: si cae la principal, las copias están en el TrueNAS, y si cae la otra, en el disco de casa.
Las copias también se declaran en git
Todo lo anterior es configuración en el repositorio de infraestructura: los Schedule de K8up, las fuentes de VolSync, las copias de CloudNativePG con su retención, la prueba de los domingos, el Compose de los contenedores de los VPS y la política de Tailscale. En los clusters lo aplica Argo CD, el agente que sincroniza cada cluster con git, al fusionar en main. Cambiar la hora de una copia o añadir un volumen es un commit que se revisa antes y queda escrito después.