使用 Tenax 還原¶
每一次還原都是一個 Restore 資源。控制台、CLI 和 API 建立的都是它。除非你要求原地還原並輸入目標的名稱,
否則還原絕不會寫入已有的資料庫。選擇一種模式:
| 需求 | 模式 | 角色 |
|---|---|---|
| 檢視資料、驗證修復、產生報表 | 沙盒(預設) | operator |
| 找回一張表或幾列資料 | 沙盒,然後複製所需內容 | operator |
| 在正式環境旁邊建一份副本(新的資料庫名) | 新資料庫 | restorer |
| 給叢集外的人一份傾印檔案 | 下載(預先簽署 URL,1 小時) | restorer |
| 將整個目標回滾 | 原地(先做安全備份) | 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
在控制台中,開啟目標,然後進入變更。每一列變更區段都有「sandbox before」和「sandbox after」連結, 會自動填好時間。
啟用 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
- 沙盒擁有獨立的名稱空間
tenax-sbx-<name>、隨機憑證和 TTL(預設 24 小時,可用tenax sandbox extend <sandbox> --by 24h延長,最長不超過策略上限)。 - 查詢控制台預設唯讀,逾時 30 秒,最多傳回 1,000 列。與目標
mask模式符合的欄會被遮罩。每次查詢都會被稽核。 - 從其他 Pod 存取:為它加上標籤
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)。
它絕不會覆蓋已有的資料庫。管理員 Secret(tenax- 字首)位於目標的名稱空間中,需要具備 CREATE DATABASE 權限。
4. 下載¶
--wait 會印出一個預先簽署 URL,指向一份已解密並重新壓縮的傾印,有效期 1 小時。這個 URL 本身就是機密:
請像對待機密一樣分享它。
5. 原地還原(最後手段)¶
tenax restore team/app --at 2026-01-02T03:04:05Z --to in-place --confirm app --credentials-secret tenax-admin --wait
- 先停止寫入方。 Tenax 不會停止應用程式。請把它們縮減到零,或切換到維護模式。
- Tenax 會對目前狀態做一次安全備份(原因為
safety)。若要跳過,需要使用--skip-safety-backup。 - 它先還原到一個暫存沙盒並檢查結果,然後替換目標的資料庫。
- 重新啟動應用程式並檢查它們。
如果出現任何問題,安全備份就是該目標的一個普通版本:用同樣的方式還原它即可。
不使用 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 實體備份是 pg_basebackup tar 串流加上 WAL 區段。
- Postgres 邏輯備份是 pg_dump -Fc 檔案,每個資料庫一個。
- MySQL 備份是 mysqldump 輸出加上 binlog 檔案。
叢集遺失或重建之後¶
還原是自動的。Tenax 自身不維護任何資料庫:儲存中儲存著每一個備份(也是唯一重要的副本),Git 中儲存著 BackupStore、策略和目標(GitOps),而 age 身分是 Secret,像其他 Secret 一樣還原即可。在新叢集上使用相同的儲存和 相同的身分安裝 Tenax,並套用相同的目標。然後:
- 控制器在啟動時檢查每個儲存(
BackupStore.status.lastImportTime)。對於每個目標,它會為最新的keepBackupObjects個備份(預設 20 個,包括已固定的)重新建立 Backup 物件。不會向儲存寫入任何內容。 更早的備份仍保留在儲存中,受保留策略約束,也仍在控制台的目錄中。 - 還原、PITR 時間窗和控制台照常工作。串流傳輸程式會從一次新的完整備份開始一條新鏈。
當目標發生變化時,以及每隔 controller.autoImport.interval(1 小時),匯入也會執行。用
controller.autoImport.enabled: false 可以關閉它。tenax catalog import [--dry-run] 使用你的 kubeconfig
手動完成同樣的操作。