Saltar a contenido

Restaurar con Tenax

Cada restauración es un recurso Restore. La consola, la CLI y la API crean uno. Las restauraciones nunca escriben en una base de datos existente, salvo que pidas en el mismo lugar y escribas el nombre del objetivo. Elige el modo:

Necesidad Modo Rol
Mirar datos, comprobar un arreglo, sacar un informe sandbox (por defecto) operator
Recuperar una tabla o unas cuantas filas sandbox, y luego copiar lo que necesites operator
Una copia junto a producción (nombre de base de datos nuevo) new restorer
Un archivo de volcado para alguien fuera del clúster download (URL prefirmada, 1 h) restorer
Revertir todo el objetivo in place (tras un respaldo de seguridad) restorer-admin

1. Encontrar el punto

tenax targets                                   # PITR windows and last backups
tenax backups team/app                          # versions (ids, times, sizes, verified, pinned)
tenax changes team/app --since 6h               # what changed when: per-table counts and DDL per segment
tenax diff <backup-a> <backup-b>                # schema and row changes between two versions

En la consola, abre el objetivo y luego Cambios. Cada fila de segmento tiene los enlaces "sandbox before" y "sandbox after", que rellenan el momento.

Con PITR sirve cualquier segundo dentro de una ventana (UTC, RFC3339): --at 2026-01-02T03:04:05Z. Sin PITR, elige un ID de respaldo: --at 20260102T020000Z-1a2b3c. Si el momento no es restaurable, Tenax explica por qué y muestra las ventanas.

2. Restaurar en un sandbox (seguro, la opción por defecto)

tenax restore team/app --at 2026-01-02T03:04:05Z --ttl 6h --wait
tenax sandbox show <sandbox>                    # connection info, expiry
tenax query <sandbox> -e "select count(*) from orders where created_at > now() - interval '1 day'"
tenax query <sandbox> -e "select * from orders where id = 42" -o csv > order42.csv
  • El sandbox recibe su propio namespace tenax-sbx-<name>, credenciales aleatorias y un TTL (24 h por defecto; amplíalo con tenax sandbox extend <sandbox> --by 24h, hasta el máximo de la política).
  • La consola de consultas es de solo lectura por defecto, con un timeout de 30 s y un límite de 1.000 filas. Las columnas que coinciden con los patrones mask del objetivo se enmascaran. Cada consulta queda auditada.
  • Desde otro pod: ponle la etiqueta tenax.run/sandbox-client: <sandbox> y conéctate a la dirección interna del clúster que muestra sandbox show.
  • Desde un portátil, si el sandbox se creó con --expose: tenax sandbox connect <sandbox> --port 15432. Esto abre el túnel a través de Cloudflare Access y muestra la cadena de conexión.
  • tenax sandbox delete <sandbox> cuando termines. Los sandboxes vencidos se borran automáticamente.

3. Restaurar en una base de datos nueva

tenax restore team/app --at 2026-01-02T03:04:05Z --to new \
  --host postgres.team.svc --database app_restored --credentials-secret tenax-admin --wait

Tenax primero restaura en un sandbox intermedio, ejecuta las comprobaciones y luego copia el resultado en la base de datos nueva con un volcado y una carga lógicos (ADR 0007). Nunca sobrescribe una base de datos existente. El secreto de administrador (prefijo tenax-) vive en el namespace del objetivo y necesita CREATE DATABASE.

4. Descarga

tenax restore team/app --at <backup-id> --to download --wait

--wait muestra una URL prefirmada a un volcado descifrado y recomprimido. Es válida durante 1 hora. La URL es un secreto: compártela como tal.

5. En el mismo lugar (último recurso)

tenax restore team/app --at 2026-01-02T03:04:05Z --to in-place --confirm app --credentials-secret tenax-admin --wait
  1. Detén primero a quienes escriben. Tenax no detiene las aplicaciones. Escálalas a cero o ponlas en modo de mantenimiento.
  2. Tenax toma un respaldo de seguridad del estado actual (motivo safety). Omitirlo requiere --skip-safety-backup.
  3. Restaura en un sandbox intermedio, comprueba el resultado y luego reemplaza las bases de datos del objetivo.
  4. Vuelve a arrancar las aplicaciones y compruébalas.

Si algo sale mal, el respaldo de seguridad es una versión normal del objetivo: restáuralo de la misma manera.

Sin la CLI

El recurso Restore es la API:

apiVersion: tenax.run/v1alpha1
kind: Restore
metadata: { name: app-incident-42, namespace: team }
spec:
  target: app
  source: { time: "2026-01-02T03:04:05Z" }     # or backupID: ..., or latest: true
  destination:
    mode: sandbox
    sandbox: { ttl: 6h }

kubectl -n team get restore app-incident-42 -w muestra el progreso: plan, descarga de la base, reproducción, comprobaciones, Succeeded.

Cuando el propio Tenax está caído

El store es la fuente de verdad y el formato de los respaldos es sencillo: - manifest.json lista cada objeto con su tamaño y su SHA-256. - Los objetos están comprimidos con zstd y cifrados con age: age -d -i key.txt obj.zst.age | zstd -d. - Los respaldos físicos de Postgres son flujos tar de pg_basebackup más segmentos de WAL. - Los respaldos lógicos de Postgres son archivos pg_dump -Fc, uno por base de datos. - Los respaldos de MySQL son la salida de mysqldump más archivos de binlog.

Tras perder o reconstruir un clúster

La recuperación es automática. Tenax no tiene base de datos propia: el store guarda cada respaldo (y es la única copia que importa), Git guarda el BackupStore, las políticas y los objetivos (GitOps), y las identidades age son secretos que restauras como cualquier otro. Instala Tenax en el clúster nuevo con el mismo store y las mismas identidades, y aplica los mismos objetivos. Después:

  1. El controlador revisa cada store al arrancar (BackupStore.status.lastImportTime). Para cada objetivo, vuelve a crear los objetos Backup de los keepBackupObjects respaldos más recientes (20 por defecto), incluidos los fijados. No se escribe nada en el store. Los respaldos más antiguos siguen en el store, sujetos a la retención, y en el catálogo de la consola.
  2. Las restauraciones, las ventanas de PITR y la consola funcionan como antes. El streamer inicia una cadena nueva a partir de un respaldo completo nuevo.

La importación también se ejecuta cuando cambian los objetivos y cada controller.autoImport.interval (1 h). Desactívala con controller.autoImport.enabled: false. tenax catalog import [--dry-run] hace lo mismo a mano, con tu kubeconfig.