Durante mucho tiempo ignoré los backups de mi cluster K3s. Tenía Proxmox Backup Server para las VMs, tenía el backup 3-2-1 para los datos importantes… pero el estado del propio cluster, los deployments, los ConfigMaps, los PersistentVolumeClaims: nada. Si el cluster petaba, tocaba reconstruir desde cero.
Llegó el momento en que un fallo de disco en uno de los nodos de Longhorn me dejó dos PVCs corruptos. No perdí datos críticos, pero me pasé un fin de semana reconfigurando servicios que debería haber tenido respaldados. Esa semana instalé Velero.
Qué es Velero y por qué importa#
Velero es una herramienta de backup y restore para clusters Kubernetes. No hace backup de los nodos en sí, sino de los recursos del cluster: Deployments, Services, ConfigMaps, Secrets, PersistentVolumeClaims… y también puede hacer snapshots de los volúmenes persistentes si tu storage provider lo soporta.
La diferencia con un backup tradicional de VMs es que Velero entiende Kubernetes. Cuando restauras, no estás restaurando un disco completo: estás recreando los objetos de la API de Kubernetes, con sus relaciones, sus namespaces y sus PVCs. Es mucho más limpio.
El storage backend puede ser cualquier cosa compatible con S3. Yo uso MinIO, que ya tenía corriendo en Phatt para otras cosas. Si tienes un NAS Synology o cualquier servidor con MinIO, te vale.
Preparar MinIO#
Necesitas un bucket dedicado para Velero. En mi caso ya tenía MinIO, así que simplemente creé el bucket y un usuario con permisos restringidos.
| |
Con esto tienes el usuario de MinIO listo. Anota las credenciales porque las necesitarás en el siguiente paso.
Instalar Velero en K3s#
Velero se instala con su propio CLI. Descárgalo desde los releases de GitHub o usa Homebrew en Mac:
| |
Crea el archivo de credenciales para MinIO:
| |
Y lanza la instalación. Adapta la URL de MinIO a tu entorno:
| |
Los parámetros importantes:
--use-volume-snapshots=false: desactivamos snapshots nativos del storage. En su lugar usamos file system backup, que funciona con cualquier storage incluyendo Longhorn.--use-node-agent: activa el agente de Velero en cada nodo para poder hacer backup de los PVCs.--default-volumes-to-fs-backup: todos los PVCs se incluyen en el backup por defecto.
Verifica que Velero está funcionando:
| |
Si el backup-location aparece como Unavailable, revisa la URL de MinIO y las credenciales. El error más común es que la URL tenga https cuando MinIO está en http.
Tu primer backup manual#
Antes de configurar schedules automáticos, haz un backup manual para verificar que todo funciona:
| |
El primer backup tarda bastante si tienes PVCs grandes. En mi caso, con unos 50GB de datos en Longhorn repartidos entre varios namespaces, tardó unos 25 minutos. Los siguientes son más rápidos porque Velero hace backups incrementales a nivel de archivo.
Cuando termine, confirma que los datos están en MinIO:
| |
Configurar schedules automáticos#
El backup manual está bien para pruebas, pero el objetivo son los backups automáticos. Yo tengo dos schedules:
Backup diario a las 5 AM, reteniendo 7 días:
| |
Backup semanal los domingos a las 4 AM, reteniendo 30 días:
| |
Para ver los schedules y confirmar que están activos:
| |
A partir de aquí Velero se encarga solo. Puedes ver el historial de backups con velero backup get y todos aparecerán listados con su estado y fecha de expiración.
La prueba de fuego: el restore#
Un backup que no has probado restaurar no es un backup. Esta es la parte que la gente se salta y luego se arrepiente.
La forma más segura de probar un restore es en un cluster de test, o restaurando en un namespace diferente para no pisar el producción. Yo lo hice así:
| |
El restore tardó unos 4 minutos. Los Pods volvieron a aparecer, los PVCs se recrearon con los datos, y Mealie arrancó sin problema con todas las recetas intactas.
Hay un detalle que me costó entender al principio: Velero restaura los objetos de Kubernetes, pero no garantiza que tus aplicaciones arranquen exactamente igual si dependían de servicios externos o de configuraciones que estaban fuera del cluster. Por eso es importante que todas las configuraciones críticas estén en ConfigMaps y Secrets dentro del cluster, no en archivos sueltos en los nodos.
Backup selectivo por namespace#
No todo tiene que entrar en el backup general. Algunos namespaces contienen datos que se regeneran solos (caches, métricas históricas de Prometheus) y no vale la pena pagar el ancho de banda y el espacio para respaldarlos.
Puedes excluir namespaces:
| |
O hacer backups específicos de namespaces críticos con más frecuencia:
| |
Yo tengo el backup general diario y además un backup cada 6 horas del namespace donde corre mi Gitea, porque perder código sería un desastre.
Consumo de espacio#
Después de un mes usando Velero, estos son mis números aproximados:
- Cluster con ~15 namespaces activos
- ~50GB de PVCs en total
- Backup diario: primer backup ~52GB, backups incrementales ~2-5GB por día
- Con 7 días de retención: ~70-80GB en MinIO para los backups diarios
- Backup semanal con 4 semanas: ~60GB adicionales
En total unos 130-140GB en MinIO. Para el espacio que tengo disponible en Phatt es perfectamente asumible.
El tamaño de los backups incrementales depende mucho de cuánto cambien tus datos. Si tienes bases de datos que escriben constantemente, el incremental puede crecer bastante. En ese caso considera excluir las bases de datos del backup de Velero y usar las herramientas propias de cada base de datos (pg_dump, mysqldump) para los dumps de datos, y dejar que Velero solo respalde la definición de los objetos de Kubernetes.
Monitorización de backups#
Velero expone métricas en formato Prometheus. Si ya tienes Grafana y Prometheus (como vimos en el post de monitorización), añade el scraping de las métricas de Velero y tendrás dashboards sobre el estado de tus backups.
Hay un dashboard oficial en el ID 11055 de Grafana que muestra el historial de backups, los backups en fallo, el tamaño total y la duración de cada backup.
Yo también tengo una alerta simple: si el último backup diario tiene más de 26 horas sin ejecutarse, me manda una notificación. Mejor enterarse antes de que pase algo que después.
Lo que aprendí por las malas#
Tres cosas que ojalá hubiera sabido antes:
La primera: el tiempo de restore es mucho mayor que el tiempo de backup. Un backup que tarda 20 minutos puede tardar 40-60 minutos en restaurarse, especialmente si hay muchos PVCs. Tenlo en cuenta para tu RTO.
La segunda: los Secrets de Kubernetes se almacenan en el backup en base64, que no es cifrado. Si el bucket de MinIO no tiene acceso restringido, cualquiera con acceso a MinIO puede leer tus Secrets. Usa credenciales fuertes en MinIO y considera cifrar el bucket.
La tercera: Velero no hace backup del etcd ni de los certificados del cluster. Si necesitas restaurar el cluster completo desde cero (no solo los workloads), necesitas un backup separado a nivel de etcd. Velero cubre los workloads y los datos; la infraestructura del propio cluster es otra historia.
Con estas consideraciones claras, Velero es exactamente lo que necesitaba. La tranquilidad de saber que si algo explota en el cluster puedo restaurar en menos de una hora vale el esfuerzo de la configuración inicial.