Tenax
PL
GitHub

Operator kopii zapasowych & przywracania dla Kubernetes · Postgres 15–17 · PostGIS · MySQL 8.4

Trzymaj mocno każdą sekundę.

Tenax tworzy kopie zapasowe baz Postgres i MySQL działających w Kubernetes we własnym buckecie S3 i strumieniuje każdą zmianę na bieżąco. Wybierz sekundę w oknie i odzyskaj dokładnie tę bazę danych w piaskownicy, którą możesz odpytywać. Szyfrowane, zanim opuszczą klaster, zbudowane jako crash-only, więc nigdy się nie zawieszają.

Jeden plik binarny, jeden chart. Twój bucket, Twoje klucze.

Okno point-in-time · team/app · polityka prod okno 7 dni · łańcuch nieprzerwany

Przywróć do
2026-10-10 14:02:37 UTC
Kopia bazowa
20261010T020712Z-4c1e
Następnie odtwórz
114
$ tenax restore team/app --at 2026-10-10T14:02:37Z --wait

Zobacz, jak się cofa, albo sam przeciągnij po oknie. Pomarańczowe znaczniki to nocne pełne kopie zapasowe; cyjanowe pasmo to strumień zmian między nimi. Ilustracja polityki prod: nocne pełne kopie, okno 7 dni.

  • 9sna przywrócenie bazy Postgres o rozmiarze 644 MiB do piaskownicy: pobranie, odszyfrowanie, odtworzenie i sprawdzenia
  • 4.2×mniej w buckecie: fizyczna kopia zapasowa 683 MiB zapisana jako 161 MiB
  • 72MiB/sprzepustowość logicznej pełnej kopii zapasowej na 4 vCPU, strumieniowo, bez plików tymczasowych
  • 20msp99 przeglądu w konsoli przy 1000 baz danych i 100 000 kopii zapasowych

Zmierzone przez make test-perf i make test-ui w środowisku testowym k3d (4 vCPU, MinIO w klastrze). Liczby są w pliku docs/PERF.md w repozytorium.

01Jak to działapięć kroków

Od zmiany na żywo do piaskownicy, którą możesz odpytywać.

Bez agenta w bazie danych, bez snapshotów woluminów. Tenax czyta zmiany przez sieć, zabezpiecza je, zanim opuszczą pod, i przywraca dowolną sekundę, gdy o to poprosisz.

  1. 01

    Strumieniowanie

    Pełne kopie zapasowe według harmonogramu oraz każda zmiana na bieżąco: własny odbiornik WAL Tenax dla Postgres, mysqlbinlog dla MySQL.

    WAL · binlog
  2. 02

    Szyfrowanie

    Każdy bajt jest kompresowany przez zstd i szyfrowany przez age Twoimi kluczami publicznymi, wewnątrz poda, w jednym przebiegu strumieniowym bez plików tymczasowych.

    zstd → age
  3. 03

    Zapis

    Równoległe uploady multipart do dowolnego bucketu zgodnego z S3, SHA-256 dla każdego obiektu i manifest zapisywany jako ostatni.

    *.zst.age · manifest.json
  4. 04

    Przywracanie co do sekundy

    Podaj czas lub ID kopii zapasowej. Tenax wybiera kopię bazową i odtwarza zmiany aż do tej dokładnej sekundy.

    --at 14:02:37
  5. 05

    Otwarcie piaskownicy

    Wynik trafia do prywatnej bazy danych z TTL i konsolą zapytań tylko do odczytu. Twoje sprawdzenia uruchamiają się, zanim przywracanie zostanie uznane za udane.

    --ttl 6h

02Przywracaniecztery miejsca docelowe

Przywracaj gdziekolwiek, bez dotykania produkcji.

Przywracanie to zasób Kubernetes jak każdy inny. Podaj czas lub ID kopii zapasowej i wybierz, dokąd ma trafić. Tenax planuje kopię bazową i zmiany do odtworzenia, a potem uruchamia Twoje sprawdzenia, zanim uzna przywracanie za udane.

SANDBOX

Tymczasowa kopia

Prywatna baza danych z TTL, danymi uwierzytelniającymi i konsolą zapytań tylko do odczytu. Sama po sobie sprząta.

--to sandbox --ttl 6h
NEW

Nowa baza danych

Przywrócona i sprawdzona w piaskownicy pośredniej, a potem skopiowana pod nową nazwę. Istniejące obiekty nigdy nie są nadpisywane.

--to new --database app_copy
IN PLACE

Prawdziwe wycofanie

Najpierw wykonuje kopię bezpieczeństwa i prosi o wpisanie nazwy celu. Wymaga roli restorer-admin.

--to in-place --confirm app
DOWNLOAD

Plik zrzutu

Odszyfrowany, skompresowany zrzut logiczny pod linkiem, który wygasa po godzinie. Rejestrowany w audycie.

--to download

03Zobaczjedna minuta

Jedna minuta, od startu do przywrócenia.

Prawdziwe polecenia i prawdziwa konsola na katalogu demonstracyjnym: wyświetl wszystkie bazy danych, zobacz, co zmieniło się w nocy, i przywróć bazę do piaskownicy.

0:58 · z dźwiękiem · 1,9 MB

Konsola

Przegląd konsoli Tenax: dziewięć baz danych z ostatnią pełną kopią zapasową, oknem point-in-time, opóźnieniem, rozmiarem zapisanym i stanem
Wszystkie bazy danych w skrócie: ostatnia pełna kopia, okno przywracania, opóźnienie strumienia, rozmiar i stan.
Strona celu w konsoli Tenax: oś czasu przywracania, trendy wierszy i rozmiarów oraz lista wersji z oznaczeniami weryfikacji
Jedna baza danych: jej oś czasu przywracania, trendy i każda wersja, z oznaczonymi zweryfikowanymi przywróceniami.
Porównanie dwóch kopii zapasowych w konsoli Tenax: dodana kolumna, opróżniona tabela, wiersze i rozmiary na tabelę
Dwie wersje obok siebie: co zostało zastosowane, które kolumny się zmieniły, wiersze i rozmiar na tabelę.

Wiedz, co zmieniło się między dwiema wersjami.

Każda kopia zapasowa zawiera inwentarz swoich tabel, wierszy i rozmiarów. Każdy segment zmian zawiera podsumowanie tego, co zrobił. Zanim cokolwiek przywrócisz, widzisz więc, która wersja wciąż miała utracone wiersze.

  • Porównania dowolnych dwóch kopii zapasowych. Zmiany schematu, liczba wierszy i rozmiar na tabelę.
  • Podsumowania zmian dla każdego segmentu WAL lub binlogu. Wstawienia, aktualizacje, usunięcia i DDL na tabelę, więc TRUNCATE o 22:48 łatwo znaleźć.
  • Zamaskowane podglądy. Przykładowe wiersze z zamaskowanymi wskazanymi kolumnami, czytelne kluczem katalogu, który nie może odszyfrować samych danych.

CLI

CLI
$ tenax targets
TARGET              ENGINE    ORG/PROJECT/ENV      LAST FULL             PITR WINDOW                                  STORED    HEALTH
analytics/events    postgres  acme/data/staging    2026-10-07 02:11:47Z  -                                            19.1GiB   ok
auth/users          postgres  acme/platform/prod   2026-10-07 02:11:06Z  2026-09-23 02:11:06Z → 2026-10-07 18:50:52Z  1.5GiB    ok
billing/invoices    mysql     acme/billing/prod    2026-10-07 02:09:03Z  2026-09-23 02:09:03Z → 2026-10-07 18:50:52Z  6.7GiB    ok
billing/ledger      postgres  acme/billing/prod    2026-10-07 02:08:22Z  2026-09-23 02:08:22Z → 2026-10-07 18:50:52Z  14.3GiB   ok
maps/geo            postgres  acme/maps/prod       2026-10-07 02:10:25Z  2026-09-23 02:10:25Z → 2026-10-07 18:50:52Z  23.3GiB   ok
shop-dev/orders-db  postgres  acme/shop/dev        2026-10-07 02:12:28Z  -                                            17.4MiB   ok
shop/catalog-db     postgres  acme/shop/prod       2026-10-07 02:07:41Z  2026-09-23 02:07:41Z → 2026-10-07 18:50:52Z  731.0MiB  ok
shop/orders-db      postgres  acme/shop/prod       2026-10-07 02:07:00Z  2026-09-23 02:07:00Z → 2026-10-07 18:50:52Z  9.6GiB    ok
web/wordpress       mysql     acme/marketing/prod  2026-10-07 02:09:44Z  2026-09-23 02:09:44Z → 2026-10-07 18:50:52Z  607.4MiB  ok
CLI
$ tenax diff 20261006T020700Z-bd79 20261007T020700Z-6da5
from  20261006T020700Z-bd79 (2026-10-06 02:07:00Z)
to    20261007T020700Z-6da5 (2026-10-07 02:07:00Z)

20261007 applied (was 20261006)
column orders.gift_note added
table audit_log +158,175 rows (+2%)
table order_items +62,923 rows (+1%)
table orders +15,655 rows (+1%)
table coupons −3,120 rows (−100%)
table customers +531 rows (+1%)

14 segments in between:
  00000001000000A100000000  18:51:32–19:20:32 · 800 commits · audit_log +3348 / ~1116 / −83 · order_items +1327 / ~442 / −33 · orders +330 / ~110 / −8 · customers +11 / ~3 / −0
  00000001000000A100000001  19:21:32–19:50:32 · 813 commits · audit_log +3352 / ~1116 / −83 · order_items +1328 / ~442 / −33 · orders +330 / ~110 / −8 · customers +13 / ~3 / −0
  00000001000000A100000002  19:51:32–20:20:32 · 826 commits · audit_log +3356 / ~1116 / −83 · order_items +1329 / ~442 / −33 · orders +330 / ~110 / −8 · customers +15 / ~3 / −0
CLI
$ tenax restore shop/orders-db --at 20261006T020700Z-bd79 --ttl 6h --reason "coupons truncated"
restore orders-db-sandbox-60414a15fc created (sandbox from 20261006T020700Z-bd79, 0 segments)
restore  shop/orders-db-sandbox-60414a15fc

$ tenax sandbox list
NAME      ENGINE    SOURCE            OWNER               PHASE         EXPIRES               IN-CLUSTER
sbx-7f3a  postgres  shop/orders-db    maria@acme.example  Ready         2026-10-08 00:37:32Z  tenax-sbx-sbx-7f3a.tenax-sandboxes.svc:5432
sbx-c210  mysql     billing/invoices  dev@acme.example    Provisioning  -

Wynik z serwera demonstracyjnego w repozytorium: go run ./hack/demo, a następnie skieruj na niego CLI lub przeglądarkę.

Konsola, CLI i API

Jedno API JSON opisane przez OpenAPI, z rolami z Cloudflare Access. Każdy zapis i każde zapytanie są rejestrowane w audycie.

Natywnie GitOps

Magazyny, polityki, cele i przywracania to CRD. Poziomy retencji, alerty i dashboard Grafana są dostarczane z chartem.

Zweryfikowane, nie wymarzone

Zaplanowane przywracania weryfikacyjne uruchamiają Twoje sprawdzenia SQL na prawdziwym przywróceniu i oznaczają kopię zapasową jako zweryfikowaną. Ich czas przywracania jest eksportowany jako metryka.

04Niezawodnośćcrash-only

Nigdy się nie zawiesza. Nie robi sobie nic z kill -9.

Kopie zapasowe zawodzą nocą w nudny sposób: zawieszony mount, martwy pod, do połowy zapisany plik. Tenax jest zbudowany tak, by żadne z nich nie mogło go zablokować ani udawać kopii zapasowej.

Nigdy się nie zawiesza

Bez montowań i urządzeń blokowych; bazy danych tylko przez sieć. Każdy strumień ma watchdog postępu, a każde narzędzie działa we własnej grupie procesów.

Crash-only

Zabij dowolny pod w dowolnej chwili. Kopia zapasowa istnieje dopiero wtedy, gdy jej manifest zostanie zapisany jako ostatni, a zestaw testów chaos zabija Tenax w trakcie kopii, by to udowodnić.

Dane przenoszą Joby, nigdy kontroler.

Kontroler tylko planuje. Movery i streamery przenoszą bajty jednym potokiem strumieniowym prosto do Twojego bucketu, a restorer je przywraca.

Delikatny dla produkcji

Jeden użytkownik bazy danych z minimalnymi uprawnieniami, który nigdy nie zapisuje. Sloty na host, limity przepustowości i ochrona obciążenia, która odkłada kopię, gdy serwer jest zajęty.

Strumieniowanie zmian

Własny odbiornik WAL Tenax na slocie replikacji dla Postgres i mysqlbinlog dla MySQL. Okno sięga teraźniejszości, nawet przy mało aktywnej bazie danych.

Szybki z założenia

Potoki strumieniowe bez plików tymczasowych, równoległe uploady multipart, wielowątkowy zstd i katalog w pamięci za konsolą, która odpowiada w milisekundach.

Tak lekki, że zapomnisz, że tam jest.

Tenax to jeden plik binarny w Go. Kontroler i API tylko planują i czytają; bajty przenoszą krótkotrwałe Joby, które kończą się po wykonaniu pracy, więc między kopiami zapasowymi w klastrze nie zostaje nic ciężkiego.

54MBjeden statyczny plik binarny: kontroler, API i konsola, movery, streamery, restorer i CLI
18MBskompresowane pobranie, bez środowiska uruchomieniowego do instalacji, bez sidecarów
21MiBpamięć kontrolera w spoczynku, przy obserwowaniu klastra baz danych
19MiBpamięć API i konsoli w spoczynku, z katalogiem w pamięci

Working set zgłaszany przez kubelet w testowym klastrze k3d (12 baz danych) po zestawach testów end-to-end i chaos; CPU w spoczynku to kilka milirdzeni. Każda baza danych z odtwarzaniem point-in-time uruchamia też streamer, około 70 MiB podczas strumieniowania.

05Bezpieczeństwoszyfrowane u źródła

Twój bucket widzi wyłącznie szyfrogram.

Szyfrowanie odbywa się w podzie, przed wysłaniem, kluczami, których Tenax nie posiada. Dostęp jest podzielony na role, a każdy zapis i każde zapytanie zostawiają wpis w audycie.

Co widzi Twój bucket
$ head -c 200 data/part-00001.zst.age
age-encryption.org/v1
-> X25519 Qm9yZWQ/IE5vdGhpbmcgdG8gc2VlIGhlcmUu…
--- 7Hc1kS0zR2QeYc…
ÌÞ#ø§ñ¹t¤¢Ý}ϰë։ÿ]Wœ3Ð÷…

Każdy obiekt danych to plik age zaszyfrowany dla Twoich odbiorców (X25519). Tylko manifest jest zwykłym JSON i nie zawiera sekretów.

  • Szyfrowane przed wysłaniem

    Każdy obiekt jest szyfrowany po stronie klienta przez age Twoimi kluczami. Bucket nigdy nie widzi tekstu jawnego, a klucz katalogu konsoli nie może czytać danych.

  • Klucz katalogu, który nie może czytać danych

    Konsola czyta inwentarze i zamaskowane podglądy osobną tożsamością katalogu. Nie może odszyfrować zrzutów, kopii bazowych, WAL ani binlogów.

  • Sprawdzane od początku do końca

    Manifest zawiera SHA-256 każdego zapisanego obiektu, sprawdzane na końcu każdego odczytu, i sam jest zapisywany jako ostatni warunkowym PUT.

  • Sekrety poza zasięgiem wzroku

    Dane uwierzytelniające baz danych trafiają do narzędzi potomnych przez zapieczętowane pliki w pamięci, nigdy przez argv ani środowisko. Logi redagują wszystko, co wygląda na sekret.

  • Role i ślad audytowy

    Logowanie przez Cloudflare Access i cztery role, od viewer do restorer-admin. Przywracanie w miejscu wymaga najwyższej roli i wpisanego potwierdzenia.

  • Zabezpieczone pody

    Bez roota, główny system plików tylko do odczytu, wszystkie capabilities odrzucone, seccomp RuntimeDefault. Pody ścieżki danych montują tylko emptyDir.

06Porównaniez zadaniem cron

Więcej niż nocny zrzut w buckecie.

Gdy musisz…skrypt cron + pg_dumpTenax
Wrócić do 09:41:27Zrzut z ostatniej nocy, do 24 h stratyDowolna sekunda w oknie
Udowodnić, że kopia się przywracaDowiedzieć się w trakcie incydentuZaplanowane przywracania weryfikacyjne z Twoimi sprawdzeniami
Znaleźć wersję z brakującymi wierszamiPrzywrócić kilka i porównaćPorównania i podsumowania zmian w konsoli
Zajrzeć bez ryzykaPrzywrócić na współdzieloną bazę stagingowąPrywatna piaskownica z TTL
Trzymać bucket w niewiedzySzyfrowanie po stronie serwera, jeśli skonfigurowaneSzyfrowanie age po stronie klienta Twoimi kluczami
Przetrwać awarię węzła w trakcie kopiiDo połowy zapisany plik, który wygląda na kompletnyNic się nie liczy, dopóki manifest nie zostanie zapisany jako ostatni
Wiedzieć, że wciąż działaCiszaAlerty o zaległych kopiach, przerwanych łańcuchach i opóźnieniu

07Instalacjaokoło dziesięciu minut

Od zera do możliwości przywracania.

  1. Zainstaluj chart

    CRD, kontroler, API i konsola, RBAC, alerty i dashboard.

    helm install tenax charts/tenax -n tenax-system --create-namespace \
      --set image.repository=registry.example.com/tenax/tenax --set image.tag=v0.1.0 \
      --set 'targetNamespaces={team-a}'
  2. Wskaż bucket i swoje klucze

    Dowolny magazyn zgodny z S3. Wygeneruj klucz age przez age-keygen i zachowaj kopię offline.

    apiVersion: tenax.run/v1alpha1
    kind: BackupStore
    metadata: { name: main }
    spec:
      s3:
        endpoint: https://s3.example.com
        region: us-east-1
        bucket: db-backups
        credentialsSecret: { namespace: tenax-system, name: tenax-s3 }
      encryption:
        ageRecipients: [age1…]   # tylko klucz publiczny; klucz prywatny pozostaje offline
  3. Zadeklaruj cel obok bazy danych

    Utwórz użytkownika bazy danych tenax za pomocą SQL z docs/sql/, a następnie zatwierdź cel w git.

    apiVersion: tenax.run/v1alpha1
    kind: BackupTarget
    metadata: { name: app, namespace: team-a }
    spec:
      engine: postgres
      endpoint: { host: postgres, port: 5432 }
      databases: [app]
      policy: prod             # nocne pełne kopie, 7-dniowe okno point-in-time
      credentials:
        secretRef: { name: tenax-postgres }
  4. Przywróć coś, celowo

    Pierwsza pełna kopia zapasowa uruchamia się sama. Potem wypróbuj to, czego masz nadzieję nigdy nie potrzebować.

    tenax targets
    tenax restore team-a/app --at 2026-10-07T09:41:27Z --wait
    tenax query <sandbox> -e "select count(*) from orders"

Pełny przewodnik, każde pole CRD i REST API znajdziesz w dokumentacji.

08FAQkonkretne odpowiedzi

O co inżynierowie pytają najpierw.

Jakie bazy danych obsługuje Tenax?

Postgres 15, 16 i 17, w tym PostGIS, z fizycznymi lub logicznymi pełnymi kopiami zapasowymi i strumieniowaniem WAL. MySQL 8.4 z logicznymi pełnymi kopiami zapasowymi i strumieniowaniem binlogu.

Jak daleko wstecz i jak precyzyjnie mogę przywracać?

Każdą pełną kopię zapasową zachowaną przez Twoje poziomy retencji i każdą sekundę w oknie point-in-time ustawionym przez politykę. Przykładowa polityka prod utrzymuje okno 7 dni oraz 14 dziennych, 8 tygodniowych, 12 miesięcznych i 5 rocznych pełnych kopii.

Czy Tenax lub mój dostawca storage może czytać moje dane?

Bucket nie może: każdy obiekt jest szyfrowany przez age dla Twoich odbiorców przed wysłaniem. Konsola czyta inwentarze kluczem katalogu, który nie może odszyfrować samych danych. Przywracanie odszyfrowuje tożsamością age, którą dostarczasz, więc przechowuj jej kopię offline.

Co się stanie, jeśli pod zginie w trakcie kopii zapasowej?

Nic, co by się liczyło. Kopia zapasowa istnieje dopiero wtedy, gdy jej manifest zostanie zapisany, po wysłaniu i zsumowaniu kontrolnym każdego obiektu. Niedokończone uruchomienie nie ma manifestu, więc nigdy nie jest oferowane do przywrócenia. Zestaw testów chaos zabija Tenax w trakcie kopii, by to udowodnić.

Czy Tenax montuje woluminy lub używa snapshotów?

Nie. Łączy się z bazami danych tylko przez sieć, a jego pody nie montują niczego poza emptyDir: bez hostPath, FUSE, iSCSI czy urządzeń blokowych i domyślnie bez PVC. Zawieszony sterownik storage nie może zablokować kopii zapasowej.

Czego Tenax potrzebuje od mojej bazy danych?

Jednego użytkownika tenax z minimalnymi uprawnieniami na bazę danych, który nigdy nie zapisuje, utworzonego za pomocą SQL z docs/sql/. Bez uprawnień replikacji Tenax nadal wykonuje logiczne kopie zapasowe i podpowiada, co nadać, aby przywracać do dowolnej sekundy.

Czy Tenax jest open source?

Jest source-available na licencji The Republic Lex Aequa License 1.0. Każdy może go bezpłatnie używać, modyfikować i redystrybuować, także produkcyjnie w firmach komercyjnych, aby chronić własne dane. Sprzedaż lub hosting jako usługi dla osób trzecich są zastrzeżone.

Przetestuj przywracanie, zanim będzie potrzebne.