Tenax
DE
GitHub

Backup- und Restore-Operator für Kubernetes · Postgres 15–17 · PostGIS · MySQL 8.4

Jede Sekunde, fest­gehalten.

Tenax sichert die Postgres- und MySQL-Datenbanken, die Sie in Kubernetes betreiben, in Ihren eigenen S3-Bucket und streamt jede Änderung, sobald sie passiert. Wählen Sie eine Sekunde im Fenster und Sie bekommen genau diese Datenbank in einer Sandbox zurück, die Sie abfragen können. Verschlüsselt, bevor die Daten den Cluster verlassen, und crash-only gebaut, damit nichts hängen bleibt.

Ein Binary, ein Chart. Ihr Bucket, Ihre Schlüssel.

Point-in-Time-Fenster · team/app · Richtlinie prod Fenster 7 Tage · Kette intakt

Wiederherstellen auf
2026-10-10 14:02:37 UTC
Basis-Backup
20261010T020712Z-4c1e
Danach einspielen
114
$ tenax restore team/app --at 2026-10-10T14:02:37Z --wait

Sehen Sie zu, wie es zurückspult, oder ziehen Sie selbst über das Fenster. Die orangefarbenen Marken sind die nächtlichen Vollsicherungen, das cyanfarbene Band ist der Änderungsstrom dazwischen. Illustration einer prod-Richtlinie: nächtliche Vollsicherung, 7-Tage-Fenster.

  • 9sum eine 644-MiB-Postgres-Datenbank in eine Sandbox zurückzuholen: laden, entschlüsseln, wiederherstellen, prüfen
  • 4.2×kleiner im Bucket: ein physisches Backup von 683 MiB, gespeichert als 161 MiB
  • 72MiB/sDurchsatz einer logischen Vollsicherung auf 4 vCPU, gestreamt ohne temporäre Dateien
  • 20msp99 der Konsolen-Übersicht mit 1.000 Datenbanken und 100.000 Backups

Gemessen mit make test-perf und make test-ui in der k3d-Testumgebung (4 vCPU, MinIO im Cluster). Die Zahlen stehen in docs/PERF.md im Repository.

01So funktioniert esfünf Schritte

Von der Live-Änderung zur Sandbox, die Sie abfragen können.

Kein Agent in Ihrer Datenbank, keine Volume-Snapshots. Tenax liest Änderungen über das Netzwerk, versiegelt sie, bevor sie den Pod verlassen, und holt jede Sekunde zurück, wenn Sie danach fragen.

  1. 01

    Streamen

    Geplante Vollsicherungen und dazu jede Änderung, sobald sie passiert: Tenax' eigener WAL-Empfänger für Postgres, mysqlbinlog für MySQL.

    WAL · binlog
  2. 02

    Verschlüsseln

    Jedes Byte wird mit zstd komprimiert und mit age für Ihre öffentlichen Schlüssel verschlüsselt, im Pod, in einem einzigen Streaming-Durchlauf ohne temporäre Dateien.

    zstd → age
  3. 03

    Speichern

    Parallele Multipart-Uploads in jeden S3-kompatiblen Bucket, ein SHA-256 für jedes Objekt, und das Manifest kommt zuletzt.

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

    Sekundengenau wiederherstellen

    Fragen Sie nach einer Uhrzeit oder einer Backup-ID. Tenax wählt die Basissicherung und spielt die Änderungen bis genau zu dieser Sekunde ein.

    --at 14:02:37
  5. 05

    Sandbox öffnen

    Das Ergebnis landet in einer privaten Datenbank mit TTL und einer schreibgeschützten Abfragekonsole. Ihre Prüfungen laufen, bevor die Wiederherstellung als erfolgreich gilt.

    --ttl 6h

02Wiederherstellenvier Ziele

Überall wiederherstellen, ohne die Produktion anzufassen.

Eine Wiederherstellung ist eine Kubernetes-Ressource wie jede andere. Geben Sie eine Zeit oder eine Backup-ID an und wählen Sie das Ziel. Tenax plant das Basis-Backup und die einzuspielenden Änderungen und führt Ihre Prüfungen aus, bevor die Wiederherstellung als erfolgreich gilt.

SANDBOX

Eine Wegwerf-Kopie

Eine private Datenbank mit TTL, Zugangsdaten und einer schreibgeschützten Abfragekonsole. Sie räumt sich selbst auf.

--to sandbox --ttl 6h
NEW

Eine neue Datenbank

In einer Staging-Sandbox wiederhergestellt und geprüft, dann unter neuem Namen kopiert. Bestehende Objekte werden nie überschrieben.

--to new --database app_copy
IN PLACE

Wirklich zurückrollen

Erstellt zuerst ein Sicherheits-Backup und verlangt, dass Sie den Namen des Ziels eintippen. Erfordert die Rolle restorer-admin.

--to in-place --confirm app
DOWNLOAD

Eine Dump-Datei

Ein entschlüsselter, komprimierter logischer Dump hinter einem Link, der nach einer Stunde abläuft. Auditiert.

--to download

03Anseheneine Minute

Eine Minute, vom Start bis zur Wiederherstellung.

Echte Befehle und die echte Konsole auf einem Demo-Katalog: alle Datenbanken auflisten, sehen, was sich über Nacht geändert hat, und in eine Sandbox zurückholen.

0:58 · mit Ton · 1,9 MB

Die Konsole

Übersicht der Tenax-Konsole: neun Datenbanken mit letzter Vollsicherung, Wiederherstellungsfenster, Verzögerung, Größe und Zustand
Alle Datenbanken auf einen Blick: letzte Vollsicherung, Wiederherstellungsfenster, Stream-Verzögerung, Größe und Zustand.
Datenbankseite der Tenax-Konsole: die wiederherstellbare Zeitleiste, Trends für Zeilen und Größe und die Versionsliste mit Prüfabzeichen
Eine Datenbank: ihre wiederherstellbare Zeitleiste, ihre Trends und jede Version, geprüfte Wiederherstellungen markiert.
Diff zwischen zwei Backups in der Tenax-Konsole: eine Spalte hinzugefügt, eine Tabelle geleert, Zeilen und Größe je Tabelle
Zwei Versionen nebeneinander: was eingespielt wurde, welche Spalten sich änderten, Zeilen und Größe je Tabelle.

Wissen, was sich zwischen zwei Versionen geändert hat.

Jedes Backup trägt ein Inventar seiner Tabellen, Zeilen und Größen. Jedes Änderungssegment trägt eine Zusammenfassung dessen, was es getan hat. So sehen Sie vor jeder Wiederherstellung, welche Version die verlorenen Zeilen noch hatte.

  • Diffs zwischen beliebigen zwei Backups. Schemaänderungen, Zeilenzahlen und Größe je Tabelle.
  • Änderungsübersicht je WAL- oder Binlog-Segment. Inserts, Updates, Deletes und DDL je Tabelle, damit ein TRUNCATE um 22:48 leicht zu finden ist.
  • Maskierte Vorschauen. Beispielzeilen mit maskierten Spalten Ihrer Wahl, lesbar mit einem Katalogschlüssel, der die Daten selbst nicht entschlüsseln kann.

Die CLI

Die 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
Die 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
Die 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  -

Ausgabe des Demo-Servers im Repository: go run ./hack/demo, dann die CLI oder einen Browser darauf richten.

Konsole, CLI und API

Eine JSON-API, beschrieben mit OpenAPI, mit Rollen aus Cloudflare Access. Jeder Schreibzugriff und jede Abfrage wird auditiert.

GitOps-nativ

Stores, Richtlinien, Ziele und Wiederherstellungen sind CRDs. Aufbewahrungsstufen, Alerts und ein Grafana-Dashboard sind im Chart enthalten.

Geprüft, nicht erhofft

Geplante Prüf-Wiederherstellungen führen Ihre SQL-Prüfungen auf einer echten Wiederherstellung aus und markieren das Backup als geprüft. Die Dauer wird als Metrik exportiert.

04Zuverlässigkeitcrash-only

Hängt nie. Steckt ein kill -9 weg.

Backups scheitern nachts auf langweilige Art: ein hängender Mount, ein toter Pod, eine halb geschriebene Datei. Tenax ist so gebaut, dass nichts davon es blockieren oder als Backup durchgehen kann.

Hängt nie

Keine Mounts, keine Block-Devices; Datenbanken nur über das Netzwerk. Jeder Strom hat einen Fortschritts-Watchdog, jedes Werkzeug läuft in seiner eigenen Prozessgruppe.

Crash-only

Beenden Sie jederzeit jeden Pod. Ein Backup existiert erst, wenn sein Manifest zuletzt geschrieben ist, und die Chaos-Suite beendet Tenax mitten im Backup, um das zu beweisen.

Daten bewegen sich in Jobs, nie im Controller.

Der Controller plant nur. Mover und Streamer tragen die Bytes durch eine einzige Streaming-Pipeline direkt in Ihren Bucket, und der Restorer holt sie zurück.

Schonend für die Produktion

Ein Datenbankbenutzer mit minimalen Rechten, der nie schreibt. Slots je Host, Bandbreitenlimits und ein Last-Wächter, der ein Backup verschiebt, wenn der Server ausgelastet ist.

Änderungsstrom

Tenaxs eigener WAL-Empfänger auf einem Replikations-Slot für Postgres und mysqlbinlog für MySQL. Das Fenster reicht bis zur Gegenwart, auch bei einer ruhigen Datenbank.

Schnell durch Konstruktion

Streaming-Pipelines ohne temporäre Dateien, parallele Multipart-Uploads, Multithread-zstd und ein Katalog im Speicher hinter einer Konsole, die in Millisekunden antwortet.

So leicht, dass man es vergisst.

Tenax ist ein einziges Go-Binary. Controller und API planen und lesen nur; Daten bewegen sich in kurzlebigen Jobs, die nach getaner Arbeit enden. Zwischen den Backups bleibt nichts Schweres im Cluster.

54MBein statisches Binary: Controller, API und Konsole, Mover, Streamer, Restorer und CLI
18MBkomprimierter Download, keine Laufzeitumgebung, keine Sidecars
21MiBSpeicher des Controllers im Ruhezustand, während er einen Cluster voller Datenbanken überwacht
19MiBSpeicher von API und Konsole im Ruhezustand, Katalog im Speicher

Working Set laut Kubelet im k3d-Testcluster (12 Datenbanken) nach End-to-End- und Chaos-Suite; die CPU im Ruhezustand liegt bei wenigen Millicores. Jede Datenbank mit Point-in-Time-Wiederherstellung betreibt zusätzlich einen Streamer, etwa 70 MiB während des Streamens.

05Sicherheitan der Quelle verschlüsselt

Ihr Bucket sieht nur Chiffretext.

Die Verschlüsselung passiert im Pod, vor dem Upload, mit Schlüsseln, die Tenax nicht besitzt. Der Zugriff ist nach Rollen getrennt, und jeder Schreibzugriff und jede Abfrage hinterlässt einen Audit-Eintrag.

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

Jedes Datenobjekt ist eine age-Datei, verschlüsselt für Ihre Empfänger (X25519). Nur das Manifest ist Klartext-JSON, und es enthält keine Geheimnisse.

  • Verschlüsselt, bevor es geht

    Jedes Objekt wird clientseitig mit age für Ihre Schlüssel verschlüsselt. Der Bucket sieht nie Klartext, und der Katalogschlüssel der Konsole kann keine Daten lesen.

  • Ein Katalogschlüssel, der keine Daten liest

    Die Konsole liest Inventare und maskierte Vorschauen mit einer eigenen Katalog-Identität. Sie kann weder Dumps noch Basissicherungen, WAL oder Binlogs entschlüsseln.

  • Durchgehend geprüft

    Das Manifest enthält für jedes gespeicherte Objekt einen SHA-256, der am Ende jedes Lesevorgangs geprüft wird, und wird selbst zuletzt mit einem bedingten PUT geschrieben.

  • Geheimnisse bleiben verborgen

    Zugangsdaten erreichen Kindprozesse über versiegelte Dateien im Speicher, nie über argv oder die Umgebung. Logs schwärzen alles, was nach einem Geheimnis aussieht.

  • Rollen und Audit-Trail

    Anmeldung über Cloudflare Access und vier Rollen, von viewer bis restorer-admin. Eine In-Place-Wiederherstellung braucht die höchste Rolle und eine getippte Bestätigung.

  • Abgeriegelte Pods

    Kein root, schreibgeschütztes Root-Dateisystem, alle Capabilities entzogen, Seccomp RuntimeDefault. Pods im Datenpfad mounten nur emptyDir.

06Im Vergleichzu einem Cronjob

Mehr als ein nächtlicher Dump im Bucket.

Wenn Sie …Cron + pg_dump-SkriptTenax
auf 09:41:27 zurück müssenDer Dump von gestern Nacht, bis zu 24 h verlorenJede Sekunde im Fenster
beweisen müssen, dass ein Backup funktioniertErfahren Sie es während des VorfallsGeplante Prüf-Wiederherstellungen mit Ihren Prüfungen
die Version mit den fehlenden Zeilen finden müssenMehrere zurückholen und nachsehenDiffs und Änderungsübersichten in der Konsole
ohne Risiko nachsehen wollenÜber ein geteiltes Staging zurückspielenEine private Sandbox mit TTL
den Bucket blind halten wollenServerseitige Verschlüsselung, falls eingerichtetClientseitige age-Verschlüsselung mit Ihren Schlüsseln
einen ausfallenden Knoten überstehen müssenEine halb geschriebene Datei, die vollständig aussiehtNichts zählt, bevor das Manifest zuletzt geschrieben ist
wissen wollen, dass es noch läuftStilleAlerts für überfällige Backups, gebrochene Ketten und Verzögerung

07Installierenetwa zehn Minuten

Von null auf wieder­herstell­bar.

  1. Chart installieren

    CRDs, Controller, API und Konsole, RBAC, Alerts und das 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. Bucket und Schlüssel angeben

    Jeder S3-kompatible Speicher. Erzeugen Sie einen age-Schlüssel mit age-keygen und bewahren Sie eine Offline-Kopie auf.

    apiVersion: tenax.republic.global/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…]   # nur der öffentliche Schlüssel; der private bleibt offline
  3. Ein Ziel neben der Datenbank deklarieren

    Legen Sie den Datenbankbenutzer tenax mit dem SQL aus docs/sql/ an und committen Sie das Ziel in Git.

    apiVersion: tenax.republic.global/v1alpha1
    kind: BackupTarget
    metadata: { name: app, namespace: team-a }
    spec:
      engine: postgres
      endpoint: { host: postgres, port: 5432 }
      databases: [app]
      policy: prod             # nächtliche Vollsicherung, 7-Tage-Fenster
      credentials:
        secretRef: { name: tenax-postgres }
  4. Etwas zurückholen, mit Absicht

    Die erste Vollsicherung startet von selbst. Probieren Sie dann aus, was Sie hoffentlich nie brauchen.

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

Die vollständige Anleitung, jedes CRD-Feld und die REST-API stehen in der Dokumentation (auf Englisch).

08FAQklare Antworten

Was Ingenieure zuerst fragen.

Welche Datenbanken unterstützt Tenax?

Postgres 15, 16 und 17, einschließlich PostGIS, mit physischen oder logischen Vollsicherungen und WAL-Streaming. MySQL 8.4 mit logischen Vollsicherungen und Binlog-Streaming.

Wie weit zurück kann ich wiederherstellen, und wie genau?

Jede Vollsicherung, die Ihre Aufbewahrungsstufen behalten, und jede Sekunde im Point-in-Time-Fenster Ihrer Richtlinie. Die Beispielrichtlinie prod hält ein 7-Tage-Fenster sowie 14 tägliche, 8 wöchentliche, 12 monatliche und 5 jährliche Vollsicherungen.

Können Tenax oder mein Speicheranbieter meine Daten lesen?

Der Bucket nicht: Jedes Objekt wird vor dem Upload mit age für Ihre Empfänger verschlüsselt. Die Konsole liest Inventare mit einem Katalogschlüssel, der die Daten selbst nicht entschlüsseln kann. Wiederherstellungen entschlüsseln mit einer age-Identität, die Sie bereitstellen; bewahren Sie eine Offline-Kopie auf.

Was passiert, wenn ein Pod mitten in einem Backup stirbt?

Nichts, was zählt. Ein Backup existiert erst, wenn sein Manifest geschrieben ist, nachdem jedes Objekt hochgeladen und geprüft wurde. Ein halber Lauf hat kein Manifest und wird daher nie zur Wiederherstellung angeboten. Die Chaos-Suite beendet Tenax mitten im Backup, um das zu beweisen.

Mountet Tenax Volumes oder nutzt es Snapshots?

Nein. Es erreicht Datenbanken nur über das Netzwerk, und seine Pods mounten nichts außer emptyDir: kein hostPath, kein FUSE, kein iSCSI, keine Blockgeräte und standardmäßig keine PVCs. Ein hängender Speichertreiber kann kein Backup blockieren.

Was braucht Tenax von meiner Datenbank?

Einen tenax-Benutzer mit minimalen Rechten pro Datenbank, der nie schreibt, angelegt mit dem SQL in docs/sql/. Ohne Replikationsrechte erstellt Tenax trotzdem logische Backups und sagt Ihnen, was Sie für sekundengenaue Wiederherstellung freigeben müssen.

Ist Tenax Open Source?

Der Quellcode ist unter der The Republic Lex Aequa License 1.0 verfügbar. Jeder darf ihn kostenlos nutzen, ändern und weitergeben, auch in Produktion und in kommerziellen Unternehmen, um die eigenen Daten zu schützen. Verkauf oder Betrieb als Dienst für Dritte ist vorbehalten.

Testen Sie Ihre Wiederherstellung, bevor Sie sie brauchen.