keeper
日本語
GitHub

Kubernetes 向けバックアップ・復元オペレーター · Postgres 15–17 · PostGIS · MySQL 8.4

データベースのすべての1秒を、復元可能に。

Keeper は Kubernetes で動かしているデータベースを任意の S3 バケットにバックアップし、変更を発生したそばからストリーミングします。過去数週間の任意の時点を選べば、そのときのデータベースが使い捨てのサンドボックスに、検証まで済んだ状態で戻ってきます。チケットを起票するより速く。

Helm でインストール ドキュメントを読む バイナリひとつ、チャートひとつ。バケットも鍵もあなたのもの。
ポイントインタイム復元の範囲 · team/app · ポリシー prod 範囲 7日間 · チェーン 正常
復元時点
2026-10-07 09:41:27 UTC
ベースバックアップ
20261007T020712Z-4c1e
続けて適用
114
$ keeper restore team/app --at 2026-10-07T09:41:27Z --wait

範囲の上をドラッグしてください。琥珀色の目盛りが毎晩のフルバックアップ、青い帯がその間の変更ストリームです。prod ポリシー(毎晩フル、7日間)のイメージです。

k3d テスト環境(4 vCPU、クラスタ内 MinIO)で make test-perf と make test-ui により計測。数値はリポジトリの docs/PERF.md にあります。

デモ1分

1分で、一覧から復元まで。

デモ用カタログに対する本物のコマンドと本物のコンソール。全データベースを一覧し、夜のあいだに何が変わったかを確認し、サンドボックスに復元します。

0:58 · 音声あり · 2.7 MB

コンソール

Keeper コンソールの概要:9つのデータベースの最新フルバックアップ、復元可能範囲、遅延、容量、状態
全データベースをひと目で:最新フルバックアップ、復元可能範囲、ストリーム遅延、容量、状態。
Keeper コンソールのデータベース画面:復元可能なタイムライン、行数と容量の推移、検証済みバッジ付きのバージョン一覧
1つのデータベース:復元可能なタイムライン、推移、すべてのバージョン。検証済みの復元に印が付きます。
Keeper コンソールの2つのバックアップの差分:追加された列、空になったテーブル、テーブルごとの行数と容量
2つのバージョンを並べて:適用されたマイグレーション、変わった列、テーブルごとの行数と容量。

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  -

リポジトリのデモサーバーの出力です:go run ./hack/demo を実行し、CLI かブラウザを向けてください。

復元4つの復元先

本番に触れずに、どこへでも復元。

復元はほかと同じ Kubernetes リソースです。時刻かバックアップ ID を指定し、復元先を選ぶだけ。Keeper がベースバックアップと適用する変更を計画し、検証を実行してから成功とします。

SANDBOX

使い捨てのコピー

TTL・認証情報・読み取り専用クエリコンソール付きのプライベートなデータベース。期限が来れば自動で片付きます。

--to sandbox --ttl 6h
NEW

新しいデータベース

ステージング用サンドボックスで復元・検証してから新しい名前でコピー。既存のオブジェクトは決して上書きしません。

--to new --database app_copy
IN PLACE

本当に巻き戻す

まず安全のためのバックアップを取り、対象名の入力を求めます。restorer-admin ロールが必要です。

--to in-place --confirm app
DOWNLOAD

ダンプファイル

復号・圧縮済みの論理ダンプを、1時間で失効するリンクで提供。監査されます。

--to download
フットプリント小さく、静か

存在を忘れるほど軽い。

Keeper は Go のバイナリひとつです。コントローラーと API は計画と読み取りだけを行い、データは処理が終われば終了する短命な Job で運ばれます。バックアップの合間にクラスタに重いものは残りません。

54MB単一の静的バイナリ:コントローラー、API とコンソール、mover、streamer、restorer、CLI
18MB圧縮ダウンロード。ランタイムもサイドカーも不要
21MiB多数のデータベースを監視中のコントローラーの待機時メモリ
19MiBカタログをメモリに載せた API とコンソールの待機時メモリ

k3d テストクラスタ(12 データベース)で E2E とカオスのスイート後に kubelet が報告したワーキングセット。待機時の CPU は数ミリコア程度です。ポイントインタイム復元を有効にした各データベースでは、ストリーミング中に約 70 MiB の streamer も動きます。

設計からして速い

一時ファイルなしのストリーミングパイプライン、並列マルチパートアップロード、マルチスレッド zstd、そしてミリ秒で応答するコンソールを支えるインメモリカタログ。

設計からして堅牢

クラッシュオンリー設計:どの Pod もいつ止まってもかまいません。状態は CRD と S3 にあり、バックアップはマニフェストが最後に書かれた時点で初めて成立し、無期限に待つ処理はありません。

確認復元の前に

2つのバージョン間で何が変わったかがわかる。

各バックアップはテーブル・行数・容量の一覧を持ち、各変更セグメントはその内容の要約を持ちます。だから復元する前に、失った行がまだ残っているバージョンがわかります。

  • 任意の2つのバックアップの差分。 スキーマ変更、行数、テーブルごとの容量。
  • WAL・binlog セグメントごとの変更要約。 テーブルごとの INSERT・UPDATE・DELETE と DDL。22:48 の TRUNCATE もすぐ見つかります。
  • マスク済みプレビュー。 指定した列をマスクしたサンプル行。データ本体は復号できないカタログ鍵で読めます。
機能標準搭載

何かが起きた夜のために。

変更ストリーミング

Postgres はレプリケーションスロット上の Keeper 独自の WAL レシーバー、MySQL は mysqlbinlog。静かなデータベースでも範囲は現在まで届きます。

願うのではなく、検証する

定期的な検証用復元が実際の復元に対して SQL チェックを実行し、バックアップを検証済みにします。復元時間はメトリクスとして出力されます。

出ていく前に暗号化

すべてのオブジェクトはクライアント側で age によりあなたの鍵へ暗号化されます。バケットは平文を見ず、コンソールのカタログ鍵ではデータを読めません。

標準で圧縮

ポリシーごとに選べるレベルの zstd を、パイプラインで一度だけ適用。ダンプツールは非圧縮で動き、データベースサーバーの CPU は使いません。

決して固まらない

マウントもブロックデバイスもなし、データベースへはネットワーク経由のみ。すべてのストリームに進捗ウォッチドッグがあり、各ツールは独自のプロセスグループで動きます。

クラッシュオンリー

どの Pod をいつ止めても大丈夫。バックアップはマニフェストが最後に書かれて初めて成立し、カオステストがバックアップ中に Keeper を止めてそれを証明します。

本番にやさしい

最小権限の読み取り専用ユーザー。ホストごとの枠、帯域制限、サーバーが混んでいればバックアップを延期する負荷ガード。

コンソール、CLI、API

OpenAPI で記述された JSON API と、Cloudflare Access によるロール。すべての書き込みとクエリが監査されます。

GitOps ネイティブ

ストア、ポリシー、ターゲット、復元はすべて CRD。保持階層、アラート、Grafana ダッシュボードがチャートに含まれます。

アーキテクチャデータの流れ

データは Job で運ばれ、コントローラーは通らない。

コントローラーは計画するだけ。mover と streamer がひとつのストリーミングパイプラインでバイトをバケットへ直接運び、restorer が取り戻します。

Postgres · MySQL あなたのクラスタ内 mover Job フルバックアップ streamer WAL · binlog ひとつのストリーミングパイプライン zstd → age → SHA-256 → 8 × multipart 一時ファイルなし、S3 からの背圧 あなたの S3 バケット manifest.json は最後 *.zst.age restorer Job 検証 → 復号 → 適用 → チェック サンドボックス · 新規 DB · その場 · ダウンロード TTL、クエリコンソール、監査付き
比較cron ジョブと

バケットに置いた夜間ダンプ以上のもの。

こんなとき…cron + pg_dump スクリプトKeeper
09:41:27 に戻したい昨夜のダンプ。最大24時間分を失う範囲内の任意の1秒
バックアップが戻せると証明したい障害の最中に判明するチェック付きの定期検証用復元
消えた行が残るバージョンを探したいいくつも復元して確かめるコンソールの差分と変更要約
リスクなしで中身を見たい共有ステージングに上書き復元TTL 付きのプライベートなサンドボックス
バケットに中身を見せたくない設定していればサーバー側暗号化あなたの鍵によるクライアント側 age 暗号化
バックアップ中のノード障害に耐えたい完全に見える書きかけのファイルマニフェストが最後に書かれるまで何も成立しない
動き続けていると知りたい沈黙遅延バックアップ、チェーン切れ、遅延へのアラート
インストール約10分

ゼロから復元可能へ。

  1. チャートをインストール

    CRD、コントローラー、API とコンソール、RBAC、アラート、ダッシュボード。

    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}'
  2. バケットと鍵を指定

    S3 互換ストレージならどれでも。age-keygen で age 鍵を作り、オフラインに控えを保管してください。

    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…]   # 公開鍵のみ。秘密鍵はオフラインに
  3. データベースの隣にターゲットを宣言

    docs/sql/ の SQL で読み取り専用ユーザーを作り、ターゲットを 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             # 毎晩フル、7日間のポイントインタイム範囲
      credentials:
        secretRef: { name: keeper-backup-postgres }
        replicationSecretRef: { name: keeper-repl-postgres }
  4. あえて何かを復元してみる

    最初のフルバックアップは自動で始まります。あとは、使わずに済むことを願うあの操作を試してください。

    keeper targets
    keeper restore team-a/app --at 2026-10-07T09:41:27Z --wait
    keeper query <sandbox> -e "select count(*) from orders"

完全なガイド、すべての CRD フィールド、REST API はドキュメント(英語)にあります。

必要になる前に、復元を試しておこう。