跳轉到

使用 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. 下載

tenax restore team/app --at <backup-id> --to download --wait

--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
  1. 先停止寫入方。 Tenax 不會停止應用程式。請把它們縮減到零,或切換到維護模式。
  2. Tenax 會對目前狀態做一次安全備份(原因為 safety)。若要跳過,需要使用 --skip-safety-backup。
  3. 它先還原到一個暫存沙盒並檢查結果,然後替換目標的資料庫。
  4. 重新啟動應用程式並檢查它們。

如果出現任何問題,安全備份就是該目標的一個普通版本:用同樣的方式還原它即可。

不使用 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,並套用相同的目標。然後:

  1. 控制器在啟動時檢查每個儲存(BackupStore.status.lastImportTime)。對於每個目標,它會為最新的 keepBackupObjects 個備份(預設 20 個,包括已固定的)重新建立 Backup 物件。不會向儲存寫入任何內容。 更早的備份仍保留在儲存中,受保留策略約束,也仍在控制台的目錄中。
  2. 還原、PITR 時間窗和控制台照常工作。串流傳輸程式會從一次新的完整備份開始一條新鏈。

當目標發生變化時,以及每隔 controller.autoImport.interval(1 小時),匯入也會執行。用 controller.autoImport.enabled: false 可以關閉它。tenax catalog import [--dry-run] 使用你的 kubeconfig 手動完成同樣的操作。