Ir al contenido
  1. Posts/

Velero: backups automáticos para tu cluster K3s

·1615 palabras·8 mins

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.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Instalar el cliente mc si no lo tienes
brew install minio/stable/mc

# Configurar el alias hacia tu servidor MinIO
mc alias set minio http://tu-servidor.local:9100 USUARIO_ADMIN PASSWORD_ADMIN

# Crear bucket
mc mb minio/velero

# Crear usuario específico para Velero
mc admin user add minio velero-user PASSWORD_SEGURA

# Crear política de acceso al bucket
cat > /tmp/velero-policy.json << 'EOF'
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:DeleteObject",
        "s3:PutObject",
        "s3:AbortMultipartUpload",
        "s3:ListMultipartUploadParts"
      ],
      "Resource": ["arn:aws:s3:::velero/*"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::velero"]
    }
  ]
}
EOF

mc admin policy create minio velero-policy /tmp/velero-policy.json
mc admin policy attach minio velero-policy --user velero-user

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:

1
2
3
4
5
6
7
# Mac
brew install velero

# Linux
wget https://github.com/vmware-tanzu/velero/releases/download/v1.14.0/velero-v1.14.0-linux-amd64.tar.gz
tar -xzf velero-v1.14.0-linux-amd64.tar.gz
sudo mv velero-v1.14.0-linux-amd64/velero /usr/local/bin/

Crea el archivo de credenciales para MinIO:

1
2
3
4
5
cat > /tmp/velero-credentials << 'EOF'
[default]
aws_access_key_id=velero-user
aws_secret_access_key=PASSWORD_SEGURA
EOF

Y lanza la instalación. Adapta la URL de MinIO a tu entorno:

1
2
3
4
5
6
7
8
9
velero install \
  --provider aws \
  --plugins velero/velero-plugin-for-aws:v1.10.0 \
  --bucket velero \
  --secret-file /tmp/velero-credentials \
  --use-volume-snapshots=false \
  --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://tu-servidor.local:9100 \
  --use-node-agent \
  --default-volumes-to-fs-backup

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:

1
2
3
4
5
kubectl get pods -n velero
# Deberías ver velero-xxxx Running y node-agent-xxxx Running en cada nodo

velero backup-location get
# Debería mostrarte tu BackupStorageLocation en estado Available

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:

1
2
3
4
5
6
7
8
# Backup de todo el cluster
velero backup create primer-backup --include-namespaces="*"

# Ver el estado
velero backup describe primer-backup

# Ver los logs si algo falla
velero backup logs primer-backup

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:

1
2
mc ls minio/velero/
# Debería aparecer una carpeta backups/primer-backup/

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:

1
2
3
4
velero schedule create daily-backup \
  --schedule="0 4 * * *" \
  --include-namespaces="*" \
  --ttl 168h0m0s

Backup semanal los domingos a las 4 AM, reteniendo 30 días:

1
2
3
4
velero schedule create weekly-backup \
  --schedule="0 3 * * 0" \
  --include-namespaces="*" \
  --ttl 720h0m0s

Para ver los schedules y confirmar que están activos:

1
velero schedule get

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í:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# Simulo que un namespace ha desaparecido (en mi caso, el de Mealie)
kubectl delete namespace mealie

# Restauro solo ese namespace desde el último backup
velero restore create test-restore-mealie \
  --from-backup daily-backup-20260320 \
  --include-namespaces mealie

# Sigo el progreso
velero restore describe test-restore-mealie --details

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:

1
2
velero backup create backup-sin-monitoring \
  --exclude-namespaces monitoring,kube-system

O hacer backups específicos de namespaces críticos con más frecuencia:

1
2
3
4
5
# Backup cada hora solo del namespace de producción
velero schedule create hourly-prod \
  --schedule="0 * * * *" \
  --include-namespaces produccion \
  --ttl 24h0m0s

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.