Backup- und Restore-Operator für Kubernetes · Postgres 15–17 · PostGIS · MySQL 8.4
Jede Sekunde Ihrer Datenbank, wiederherstellbar.
Keeper sichert die Datenbanken, die Sie in Kubernetes betreiben, in jeden S3-Bucket und streamt jede Änderung, sobald sie passiert. Wählen Sie einen Moment der letzten Wochen, und Sie bekommen genau diese Datenbank in einer Wegwerf-Sandbox zurück, Prüfungen bereits ausgeführt, schneller als Sie ein Ticket eröffnen.
- Wiederherstellen auf
- 2026-10-07 09:41:27 UTC
- Basis-Backup
- 20261007T020712Z-4c1e
- Danach einspielen
- 114
$ keeper restore team/app --at 2026-10-07T09:41:27Z --wait
Ziehen Sie über das Fenster. Die bernsteinfarbenen Marken sind die nächtlichen Vollsicherungen, das blaue 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.
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.
Die Konsole
Die CLI
$ keeper 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
$ keeper 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
$ keeper 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 $ keeper 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 keeper-sbx-sbx-7f3a.keeper-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.
Ü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. Keeper plant das Basis-Backup und die einzuspielenden Änderungen und führt Ihre Prüfungen aus, bevor die Wiederherstellung als erfolgreich gilt.
Eine Wegwerf-Kopie
Eine private Datenbank mit TTL, Zugangsdaten und einer schreibgeschützten Abfragekonsole. Sie räumt sich selbst auf.
--to sandbox --ttl 6hEine neue Datenbank
In einer Staging-Sandbox wiederhergestellt und geprüft, dann unter neuem Namen kopiert. Bestehende Objekte werden nie überschrieben.
--to new --database app_copyWirklich 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 appEine Dump-Datei
Ein entschlüsselter, komprimierter logischer Dump hinter einem Link, der nach einer Stunde abläuft. Auditiert.
--to downloadSo leicht, dass man es vergisst.
Keeper 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.
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.
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.
Zuverlässig durch Konstruktion
Crash-only: Jeder Pod kann jederzeit sterben. Der Zustand liegt in CRDs und S3, ein Backup existiert erst, wenn sein Manifest zuletzt geschrieben ist, und nichts wartet ewig.
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.
Gebaut für die Nacht, in der etwas schiefgeht.
Änderungsstrom
Keepers 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.
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.
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.
Standardmäßig komprimiert
zstd mit der Stufe, die Sie je Richtlinie wählen, einmal in der Pipeline angewendet. Dump-Werkzeuge laufen unkomprimiert, und der Datenbankserver verbraucht dafür keine CPU.
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 Keeper mitten im Backup, um das zu beweisen.
Schonend für die Produktion
Schreibgeschützte Benutzer mit minimalen Rechten. Slots je Host, Bandbreitenlimits und ein Last-Wächter, der ein Backup verschiebt, wenn der Server ausgelastet ist.
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.
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.
Mehr als ein nächtlicher Dump im Bucket.
| Wenn Sie … | Cron + pg_dump-Skript | Keeper |
|---|---|---|
| auf 09:41:27 zurück müssen | Der Dump von gestern Nacht, bis zu 24 h verloren | Jede Sekunde im Fenster |
| beweisen müssen, dass ein Backup funktioniert | Erfahren Sie es während des Vorfalls | Geplante Prüf-Wiederherstellungen mit Ihren Prüfungen |
| die Version mit den fehlenden Zeilen finden müssen | Mehrere zurückholen und nachsehen | Diffs und Änderungsübersichten in der Konsole |
| ohne Risiko nachsehen wollen | Über ein geteiltes Staging zurückspielen | Eine private Sandbox mit TTL |
| den Bucket blind halten wollen | Serverseitige Verschlüsselung, falls eingerichtet | Clientseitige age-Verschlüsselung mit Ihren Schlüsseln |
| einen ausfallenden Knoten überstehen müssen | Eine halb geschriebene Datei, die vollständig aussieht | Nichts zählt, bevor das Manifest zuletzt geschrieben ist |
| wissen wollen, dass es noch läuft | Stille | Alerts für überfällige Backups, gebrochene Ketten und Verzögerung |
Von null auf wiederherstellbar.
Chart installieren
CRDs, Controller, API und Konsole, RBAC, Alerts und das Dashboard.
helm install keeper charts/keeper -n keeper-system --create-namespace \ --set image.repository=registry.example.com/keeper/keeper --set image.tag=v0.1.0 \ --set 'targetNamespaces={team-a}'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: keeper.republic.global/v1alpha1 kind: BackupStore metadata: { name: main } spec: s3: endpoint: https://s3.example.com region: us-east-1 bucket: db-backups credentialsSecret: { namespace: keeper-system, name: keeper-s3 } encryption: ageRecipients: [age1…] # nur der öffentliche Schlüssel; der private bleibt offline
Ein Ziel neben der Datenbank deklarieren
Legen Sie die schreibgeschützten Benutzer mit dem SQL aus docs/sql/ an und committen Sie das Ziel in Git.
apiVersion: keeper.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: keeper-backup-postgres } replicationSecretRef: { name: keeper-repl-postgres }
Etwas zurückholen, mit Absicht
Die erste Vollsicherung startet von selbst. Probieren Sie dann aus, was Sie hoffentlich nie brauchen.
keeper targets keeper restore team-a/app --at 2026-10-07T09:41:27Z --wait keeper query <sandbox> -e "select count(*) from orders"
Die vollständige Anleitung, jedes CRD-Feld und die REST-API stehen in der Dokumentation (auf Englisch).