Operator pencadangan & pemulihan untuk Kubernetes · Postgres 15–17 · PostGIS · MySQL 8.4
Genggam erat setiap detik.
Tenax mencadangkan basis data Postgres dan MySQL yang Anda jalankan di Kubernetes ke bucket S3 milik Anda sendiri dan mengalirkan setiap perubahan saat terjadi. Pilih satu detik di dalam jendela dan dapatkan kembali basis data persis seperti saat itu di sandbox yang bisa Anda kueri. Dienkripsi sebelum meninggalkan klaster, dibangun crash-only sehingga tidak pernah macet.
Satu biner, satu chart. Bucket Anda, kunci Anda.
- Pulihkan ke
- 2026-10-10 14:02:37 UTC
- Cadangan dasar
- 20261010T020712Z-4c1e
- Lalu putar ulang
- 114
$ tenax restore team/app --at 2026-10-10T14:02:37Z --wait
Saksikan ia memutar mundur, atau geser sendiri di sepanjang jendela. Tanda bara adalah cadangan penuh setiap malam; pita sian adalah aliran perubahan di antaranya. Ilustrasi kebijakan prod: cadangan penuh setiap malam, jendela 7 hari.
- 9suntuk memulihkan basis data Postgres 644 MiB ke sandbox: mengambil, mendekripsi, memulihkan, dan menjalankan pemeriksaan
- 4.2×lebih kecil di bucket: cadangan fisik 683 MiB disimpan sebagai 161 MiB
- 72MiB/sthroughput cadangan penuh logis pada 4 vCPU, dialirkan tanpa berkas sementara
- 20msp99 untuk ikhtisar konsol dengan 1.000 basis data dan 100.000 cadangan
Diukur dengan make test-perf dan make test-ui pada harness uji k3d (4 vCPU, MinIO di dalam klaster). Angka-angkanya ada di docs/PERF.md repositori.
01Cara kerjalima langkah
Dari perubahan langsung ke sandbox yang bisa Anda kueri.
Tanpa agen di dalam basis data Anda, tanpa snapshot volume. Tenax membaca perubahan melalui jaringan, menyegelnya sebelum meninggalkan pod, dan mengembalikan detik mana pun saat Anda memintanya.
- 01
Alirkan
Cadangan penuh terjadwal, ditambah setiap perubahan saat terjadi: penerima WAL milik Tenax sendiri untuk Postgres, mysqlbinlog untuk MySQL.
WAL · binlog - 02
Enkripsi
Setiap byte dikompresi dengan zstd dan dienkripsi dengan age ke kunci publik Anda, di dalam pod, dalam satu lintasan streaming tanpa berkas sementara.
zstd → age - 03
Simpan
Unggahan multipart paralel ke bucket apa pun yang kompatibel dengan S3, SHA-256 untuk setiap objek, dan manifest ditulis paling akhir.
*.zst.age · manifest.json - 04
Pulihkan sampai ke detiknya
Minta waktu atau ID cadangan. Tenax memilih cadangan dasar dan memutar ulang perubahan sampai detik yang tepat itu.
--at 14:02:37 - 05
Buka sandbox
Hasilnya mendarat di basis data pribadi dengan TTL dan konsol kueri baca-saja. Pemeriksaan Anda berjalan sebelum pemulihan dianggap berhasil.
--ttl 6h
02Pemulihanempat tujuan
Pulihkan ke mana saja, tanpa menyentuh produksi.
Pemulihan adalah resource Kubernetes seperti yang lain. Minta waktu atau ID cadangan, lalu pilih tujuannya. Tenax merencanakan cadangan dasar dan perubahan yang akan diputar ulang, lalu menjalankan pemeriksaan Anda sebelum menyatakan pemulihan berhasil.
Salinan sekali pakai
Basis data pribadi dengan TTL, kredensial, dan konsol kueri baca-saja. Ia membersihkan dirinya sendiri.
--to sandbox --ttl 6hBasis data baru
Dipulihkan dan diperiksa di sandbox staging, lalu disalin ke nama baru. Objek yang sudah ada tidak pernah ditimpa.
--to new --database app_copyKembalikan sungguhan
Membuat cadangan pengaman terlebih dahulu dan meminta Anda mengetik nama target. Memerlukan peran restorer-admin.
--to in-place --confirm appBerkas dump
Dump logis terdekripsi dan terkompresi di balik tautan yang kedaluwarsa dalam satu jam. Diaudit.
--to download03Lihatsatu menit
Satu menit, dari awal sampai pemulihan.
Perintah sungguhan dan konsol sungguhan pada katalog demo: tampilkan semua basis data, lihat apa yang berubah semalam, pulihkan ke sandbox.
Konsol
Ketahui apa yang berubah di antara dua versi.
Setiap cadangan membawa inventaris tabel, baris, dan ukurannya. Setiap segmen perubahan membawa ringkasan apa yang dilakukannya. Jadi sebelum memulihkan apa pun, Anda bisa melihat versi mana yang masih memiliki baris yang hilang.
- Diff antara dua cadangan mana pun. Perubahan skema, jumlah baris, dan ukuran per tabel.
- Ringkasan perubahan per segmen WAL atau binlog. Insert, update, delete, dan DDL per tabel, sehingga TRUNCATE pada pukul 22:48 mudah ditemukan.
- Pratinjau tersamar. Contoh baris dengan kolom yang Anda tentukan disamarkan, dapat dibaca dengan kunci katalog yang tidak bisa mendekripsi data itu sendiri.
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
$ 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
$ 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 -
Keluaran dari server demo di repositori: go run ./hack/demo, lalu arahkan CLI atau browser ke sana.
Konsol, CLI, dan API
Satu API JSON yang dijelaskan dengan OpenAPI, dengan peran dari Cloudflare Access. Setiap penulisan dan setiap kueri diaudit.
Asli GitOps
Store, kebijakan, target, dan pemulihan adalah CRD. Tingkat retensi, peringatan, dan dasbor Grafana disertakan dalam chart.
Terverifikasi, bukan sekadar harapan
Pemulihan verifikasi terjadwal menjalankan pemeriksaan SQL Anda pada pemulihan sungguhan dan menandai cadangan sebagai terverifikasi. Waktu pemulihannya diekspor sebagai metrik.
04Keandalancrash-only
Tidak pernah macet. Santai menghadapi kill -9.
Pencadangan gagal di malam hari dengan cara yang membosankan: mount yang macet, pod yang mati, berkas yang setengah tertulis. Tenax dibangun agar tak satu pun dari itu bisa membuatnya tersangkut atau dianggap sebagai cadangan.
- data/part-00001.zst.age
- data/part-00002.zst.age
- data/part-00003.zst.age
- manifest.json
- data/part-00001.zst.age
- data/part-00002.zst.age
- data/part-00003.zst.age
- manifest.json
Tidak pernah macet
Tanpa mount atau block device; basis data hanya melalui jaringan. Setiap aliran punya watchdog kemajuan, dan setiap alat berjalan di process group-nya sendiri.
Crash-only
Matikan pod mana pun kapan saja. Cadangan baru ada setelah manifest-nya ditulis paling akhir, dan rangkaian uji chaos mematikan Tenax di tengah pencadangan untuk membuktikannya.
Data berpindah di Job, tidak pernah di controller.
Controller hanya menjadwalkan. Mover dan streamer membawa byte melalui satu pipeline streaming langsung ke bucket Anda, dan restorer mengembalikannya.
Ramah terhadap produksi
Satu pengguna basis data dengan hak minimum yang tidak pernah menulis. Slot per host, batas bandwidth, dan penjaga beban yang menunda pencadangan saat server sibuk.
Streaming perubahan
Penerima WAL milik Tenax sendiri pada replication slot untuk Postgres dan mysqlbinlog untuk MySQL. Jendelanya menjangkau saat ini, bahkan pada basis data yang sepi.
Cepat sejak rancangannya
Pipeline streaming tanpa berkas sementara, unggahan multipart paralel, zstd multi-thread, dan katalog di memori di balik konsol yang menjawab dalam hitungan milidetik.
Cukup kecil hingga Anda lupa ia ada.
Tenax adalah satu biner Go. Controller dan API hanya menjadwalkan dan membaca; byte berpindah di Job berumur pendek yang keluar setelah selesai, sehingga tidak ada beban berat di klaster Anda di antara pencadangan.
Working set yang dilaporkan kubelet di klaster uji k3d (12 basis data) setelah rangkaian uji end-to-end dan chaos; CPU saat diam hanya beberapa milicore. Setiap basis data dengan pemulihan point-in-time juga menjalankan streamer, sekitar 70 MiB selama mengalirkan.
05Keamananterenkripsi di sumbernya
Bucket Anda hanya pernah melihat ciphertext.
Enkripsi terjadi di dalam pod, sebelum unggahan, ke kunci yang tidak dipegang Tenax. Akses dibagi menurut peran, dan setiap penulisan serta setiap kueri meninggalkan catatan audit.
$ head -c 200 data/part-00001.zst.age age-encryption.org/v1 -> X25519 Qm9yZWQ/IE5vdGhpbmcgdG8gc2VlIGhlcmUu… --- 7Hc1kS0zR2QeYc… ÌÞ#ø§ñ¹t¤¢Ý}ϰë։ÿ]Wœ3Ð÷…
Setiap objek data adalah berkas age yang dienkripsi ke penerima Anda (X25519). Hanya manifest yang berupa JSON biasa, dan isinya tidak memuat rahasia.
Dienkripsi sebelum keluar
Setiap objek dienkripsi di sisi klien dengan age ke kunci Anda. Bucket tidak pernah melihat plaintext, dan kunci katalog konsol tidak dapat membaca data.
Kunci katalog yang tidak dapat membaca data
Konsol membaca inventaris dan pratinjau tersamar dengan identitas katalog terpisah. Identitas itu tidak dapat mendekripsi dump, cadangan dasar, WAL, maupun binlog.
Diperiksa dari ujung ke ujung
Manifest memuat SHA-256 untuk setiap objek tersimpan, diperiksa di akhir setiap pembacaan, dan manifest sendiri ditulis paling akhir dengan PUT bersyarat.
Rahasia tetap tersembunyi
Kredensial basis data sampai ke alat turunan melalui berkas tersegel di memori, tidak pernah lewat argv atau environment. Log menyamarkan apa pun yang tampak seperti rahasia.
Peran dan jejak audit
Masuk melalui Cloudflare Access dan empat peran, dari viewer hingga restorer-admin. Pemulihan di tempat memerlukan peran tertinggi dan konfirmasi yang diketik.
Pod yang dikunci rapat
Non-root, filesystem root baca-saja, semua capability dilepas, seccomp RuntimeDefault. Pod jalur data hanya me-mount emptyDir.
06Dibandingkandengan cron job
Lebih dari sekadar dump malam hari di bucket.
| Saat Anda perlu… | skrip cron + pg_dump | Tenax |
|---|---|---|
| Kembali ke 09:41:27 | Dump semalam, hingga 24 jam hilang | Detik mana pun di dalam jendela |
| Membuktikan cadangan bisa dipulihkan | Baru ketahuan saat insiden | Pemulihan verifikasi terjadwal dengan pemeriksaan Anda |
| Menemukan versi dengan baris yang hilang | Pulihkan beberapa dan periksa | Diff dan ringkasan perubahan di konsol |
| Melihat tanpa risiko | Pulihkan menimpa basis data staging bersama | Sandbox pribadi dengan TTL |
| Menjaga bucket tetap buta | Enkripsi sisi server, jika dikonfigurasi | Enkripsi age sisi klien ke kunci Anda |
| Bertahan saat node mati di tengah pencadangan | Berkas setengah jadi yang tampak lengkap | Tidak ada yang dihitung sampai manifest ditulis paling akhir |
| Tahu bahwa semuanya masih berjalan | Sunyi | Peringatan untuk cadangan terlambat, rantai terputus, dan lag |
07Instalasisekitar sepuluh menit
Dari nol sampai bisa dipulihkan.
Pasang chart
CRD, controller, API dan konsol, RBAC, peringatan, dan dasbor.
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}'Arahkan ke bucket dan kunci Anda
Store apa pun yang kompatibel dengan S3. Buat kunci age dengan age-keygen dan simpan salinan 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…] # hanya kunci publik; kunci privat tetap offline
Deklarasikan target di samping basis data
Buat pengguna basis data tenax dengan SQL di docs/sql/, lalu commit target ke 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 # cadangan penuh setiap malam, jendela point-in-time 7 hari credentials: secretRef: { name: tenax-postgres }
Pulihkan sesuatu, dengan sengaja
Cadangan penuh pertama dimulai dengan sendirinya. Lalu coba hal yang Anda harap tidak pernah dibutuhkan.
tenax targets tenax restore team-a/app --at 2026-10-07T09:41:27Z --wait tenax query <sandbox> -e "select count(*) from orders"
Panduan lengkap, setiap field CRD, dan REST API ada di dokumentasi.
08FAQjawaban lugas
Yang pertama kali ditanyakan engineer.
Basis data apa saja yang didukung Tenax?
Postgres 15, 16, dan 17, termasuk PostGIS, dengan cadangan penuh fisik atau logis dan streaming WAL. MySQL 8.4 dengan cadangan penuh logis dan streaming binlog.
Seberapa jauh ke belakang saya bisa memulihkan, dan seberapa presisi?
Cadangan penuh mana pun yang disimpan tingkat retensi Anda, dan detik mana pun di dalam jendela point-in-time yang ditetapkan kebijakan Anda. Contoh kebijakan prod menyimpan jendela 7 hari serta 14 cadangan penuh harian, 8 mingguan, 12 bulanan, dan 5 tahunan.
Bisakah Tenax atau penyedia penyimpanan saya membaca data saya?
Bucket tidak bisa: setiap objek dienkripsi dengan age ke penerima Anda sebelum diunggah. Konsol membaca inventaris dengan kunci katalog yang tidak dapat mendekripsi data itu sendiri. Pemulihan mendekripsi dengan identitas age yang Anda berikan, jadi simpan salinan offline-nya.
Apa yang terjadi jika pod mati di tengah pencadangan?
Tidak ada yang berarti. Cadangan baru ada setelah manifest-nya ditulis, setelah setiap objek diunggah dan di-checksum. Proses yang setengah jalan tidak punya manifest, jadi tidak pernah ditawarkan untuk pemulihan. Rangkaian uji chaos mematikan Tenax di tengah pencadangan untuk membuktikannya.
Apakah Tenax me-mount volume atau memakai snapshot?
Tidak. Tenax menjangkau basis data hanya melalui jaringan, dan pod-nya tidak me-mount apa pun selain emptyDir: tanpa hostPath, FUSE, iSCSI, atau block device, dan tanpa PVC secara bawaan. Driver penyimpanan yang macet tidak dapat membuat pencadangan tersangkut.
Apa yang dibutuhkan Tenax dari basis data saya?
Satu pengguna tenax dengan hak minimum per basis data yang tidak pernah menulis, dibuat dengan SQL di docs/sql/. Tanpa hak replikasi, Tenax tetap membuat cadangan logis dan memberi tahu Anda apa yang perlu diberikan agar bisa memulihkan ke detik mana pun.
Apakah Tenax open source?
Kode sumbernya tersedia di bawah The Republic Lex Aequa License 1.0. Siapa pun boleh memakai, memodifikasi, dan mendistribusikannya ulang secara gratis, termasuk di produksi pada perusahaan komersial, untuk melindungi data mereka sendiri. Menjual atau menghostingnya sebagai layanan untuk pihak ketiga tidak diizinkan.