Перейти к содержанию

Восстановление с Tenax

Каждое восстановление — это ресурс Restore. Его создают и консоль, и CLI, и API. Восстановление никогда не пишет в существующую базу данных, если только вы не выбрали на месте и не ввели имя цели. Выберите режим:

Задача Режим Роль
Посмотреть данные, проверить исправление, сделать отчёт песочница (по умолчанию) operator
Вернуть одну таблицу или несколько строк песочница, затем скопировать нужное operator
Копия рядом с продакшеном (новое имя базы данных) new restorer
Файл дампа для кого-то за пределами кластера download (presigned URL, 1 ч) restorer
Откатить цель целиком in place (после страховочной резервной копии) restorer-admin

1. Найдите точку

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

В консоли откройте цель, затем Изменения. В каждой строке сегмента есть ссылки «песочница до» и «песочница после», которые подставляют время.

С PITR подходит любая секунда внутри окна (UTC, RFC3339): --at 2026-01-02T03:04:05Z. Без PITR выберите id резервной копии: --at 20260102T020000Z-1a2b3c. Если момент нельзя восстановить, Tenax объясняет почему и выводит окна.

2. Восстановление в песочницу (безопасно, по умолчанию)

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
  • Песочница получает собственный namespace tenax-sbx-<name>, случайные учётные данные и TTL (по умолчанию 24 ч, продлевается командой tenax sandbox extend <sandbox> --by 24h до максимума политики).
  • Консоль запросов по умолчанию работает только на чтение, с тайм-аутом 30 с и лимитом 1 000 строк. Столбцы, подходящие под шаблоны mask цели, маскируются. Каждый запрос записывается в аудит.
  • Из другого пода: добавьте ему метку tenax.run/sandbox-client: <sandbox> и подключитесь к адресу внутри кластера, который выводит sandbox show.
  • С ноутбука, если песочница создана с --expose: tenax sandbox connect <sandbox> --port 15432. Команда открывает туннель через Cloudflare Access и выводит строку подключения.
  • Когда закончите, выполните tenax sandbox delete <sandbox>. Истёкшие песочницы удаляются автоматически.

3. Восстановление в новую базу данных

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 восстанавливает данные в промежуточную песочницу, выполняет проверки, а затем копирует результат в новую базу данных логическим дампом и загрузкой (ADR 0007). Существующая база данных никогда не перезаписывается. Секрет администратора (префикс tenax-) находится в namespace цели и должен иметь право CREATE DATABASE.

4. Скачивание

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

--wait выводит presigned URL на расшифрованный и заново сжатый дамп. Он действителен 1 час. URL — это секрет: обращайтесь с ним соответственно.

5. На месте (крайняя мера)

tenax restore team/app --at 2026-01-02T03:04:05Z --to in-place --confirm app --credentials-secret tenax-admin --wait
  1. Сначала остановите тех, кто пишет. Tenax не останавливает приложения. Масштабируйте их до нуля или переведите в режим обслуживания.
  2. Tenax делает страховочную резервную копию текущего состояния (причина safety). Чтобы её пропустить, нужен --skip-safety-backup.
  3. Данные восстанавливаются в промежуточную песочницу, результат проверяется, затем базы данных цели заменяются.
  4. Снова запустите приложения и проверьте их.

Если что-то пошло не так, страховочная резервная копия — обычная версия цели: восстановите её тем же способом.

Без CLI

Ресурс Restore и есть 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 показывает прогресс: план, загрузка базы, применение изменений, проверка, Succeeded.

Когда не работает сам Tenax

Источник истины — хранилище, а формат резервных копий простой: - manifest.json перечисляет все объекты с их размером и SHA-256. - Объекты сжаты zstd и зашифрованы age: age -d -i key.txt obj.zst.age | zstd -d. - Физические резервные копии Postgres — это tar-потоки pg_basebackup плюс сегменты WAL. - Логические резервные копии Postgres — файлы pg_dump -Fc, по одному на базу данных. - Резервные копии MySQL — вывод mysqldump плюс файлы binlog.

После потери или пересоздания кластера

Восстановление происходит автоматически. У Tenax нет собственной базы данных: хранилище содержит все резервные копии (и это единственная копия, которая имеет значение), Git хранит BackupStore, политики и цели (GitOps), а идентичности age — это секреты, которые вы восстанавливаете, как любые другие. Установите Tenax в новый кластер с тем же хранилищем и теми же идентичностями и примените те же цели. Затем:

  1. При запуске контроллер проверяет каждое хранилище (BackupStore.status.lastImportTime). Для каждой цели он пересоздаёт объекты Backup для keepBackupObjects самых новых резервных копий (по умолчанию 20), включая закреплённые. В хранилище ничего не записывается. Более старые копии остаются в хранилище, под политикой хранения, и в каталоге консоли.
  2. Восстановления, окна PITR и консоль работают как прежде. Streamer начинает новую цепочку со свежей полной резервной копии.

Импорт также запускается при изменении целей и каждые controller.autoImport.interval (1 ч). Отключается он через controller.autoImport.enabled: false. tenax catalog import [--dry-run] делает то же самое вручную, используя ваш kubeconfig.