Tenax で復元する¶
すべての復元は Restore リソースです。コンソール、CLI、API のいずれもこれを作成します。インプレース を指定して
ターゲット名を入力しない限り、復元が既存のデータベースに書き込むことはありません。モードを選びます。
| 目的 | モード | ロール |
|---|---|---|
| データを見る、修正を確認する、レポートを実行する | サンドボックス (デフォルト) | operator |
| テーブルひとつや数行を取り戻す | サンドボックスに復元し、必要なものをコピー | operator |
| 本番の隣にコピーを作る (新しいデータベース名) | new | 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 があれば、ウィンドウ内の任意の 1 秒を指定できます (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
- サンドボックスには専用の Namespace
tenax-sbx-<name>、ランダムな認証情報、TTL が与えられます (デフォルト 24 時間。tenax sandbox extend <sandbox> --by 24hでポリシーの上限まで延長できます)。 - クエリコンソールはデフォルトで読み取り専用で、タイムアウトは 30 秒、上限は 1,000 行です。ターゲットの
maskパターンに 一致する列はマスクされます。すべてのクエリは監査されます。 - 別の Pod から: その Pod に
tenax.run/sandbox-client: <sandbox>ラベルを付け、sandbox showが表示する クラスター内アドレスに接続します。 - ノート PC から (サンドボックスが
--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- プレフィックス) は
ターゲットの Namespace に置き、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 と同じように復元する シークレットです。新しいクラスターに同じストアと同じアイデンティティで Tenax をインストールし、同じターゲットを適用します。その後:
- コントローラーは起動時に各ストアを確認します (
BackupStore.status.lastImportTime)。ターゲットごとに、最新のkeepBackupObjects件 (デフォルト 20) のバックアップの Backup オブジェクトを、ピンを含めて再作成します。ストアには何も 書き込みません。それより古いバックアップはストアに残り、保持ポリシーの対象となり、コンソールのカタログにも表示されます。 - 復元、PITR ウィンドウ、コンソールは以前と同じように動きます。ストリーマーは新しいフルバックアップから新しいチェーンを開始します。
インポートはターゲットが変わったときと、controller.autoImport.interval (1 時間) ごとにも実行されます。
controller.autoImport.enabled: false で無効にできます。tenax catalog import [--dry-run] は同じことを手動で、
あなたの kubeconfig を使って行います。