コンテンツにスキップ

サンドボックスとクエリ

サンドボックスは、バックアップまたはウィンドウ内の任意の 1 秒から復元された、専用の使い捨てデータベースです。 見るだけなら本番環境を危険にさらすことがないため、これがデフォルトの復元先です。

tenax restore team-a/app --at 2026-10-07T09:41:27Z --ttl 6h --wait
tenax sandbox list
tenax sandbox show <sandbox>

サンドボックスとは

  • ターゲットと同じエンジンとバージョン (ターゲットの spec.sandbox.image) のデータベース Pod です。Tenax のサンドボックス用 Namespace に置かれ、生成された認証情報とデフォルト拒否の NetworkPolicy を持ちます。
  • TTL があります (sandbox.defaultTTL、最大 sandbox.maxTTL。どちらもポリシーごととチャート全体で設定可能)。期限が切れると Tenax はサンドボックスとそのストレージを削除します。tenax sandbox extend <sandbox> --by 24h で時間を延ばし、 tenax sandbox delete <sandbox> で早めに終了できます。
  • 作成を依頼した人が所有者になり、それに対するすべての操作は監査されます。

クエリ

コンソールの クエリ ページと tenax query は、Tenax のクエリプロキシを通して SQL を実行します。デフォルトでは読み取り専用です。

tenax query <sandbox> -e "select count(*) from orders where created_at > now() - interval '1 day'"
tenax query <sandbox> -e "select * from coupons" -o csv > coupons.csv

各クエリには 30 秒の制限があり、返すのは最大 1,000 行です。--write で書き込みを許可できます (サンドボックスのみ)。

エディターでは Ctrl+Enter (Mac では Cmd+Enter) でクエリを実行します。選択範囲がある場合は選択したテキストだけを実行します。 補完はキーワード、関数、テーブル、列を候補に出します。2 文字入力すると開き、alias. の後ではそのテーブルの列を、 schema. の後ではそのスキーマのテーブルを一覧し、Ctrl+Space でどこでも開けます。Tab または Enter で候補を選び、 Esc で閉じます。それ以外のときは Tab でインデントします。

コンソールは各エンジンの SQL (現在は PostgreSQL と MySQL) を扱います。結果の値はデータベースが表示するとおりに表示されます。

サイズ設定

各サンドボックスは専用の Namespace にあるデータベース Pod です。割り当てられるリソースは、次のうち最初に設定されている場所から決まります。

  1. 復元: Restore ページの CPU、メモリ、ディスク、ストレージクラス フィールド (グレーの値は空欄のままにした場合に 割り当てられる値です)、tenax restore … --cpu 2 --memory 8Gi --size 50Gi --storage-class local-path、または Restore の spec.destination.sandbox。
  2. ターゲット: BackupTarget の spec.sandbox.cpu、memory、sizeLimit、storageClass。
  3. インストール: チャートの sandbox.resources。
  4. 組み込みの値: CPU 100m、メモリ 256Mi のリクエストと 1Gi のリミット、そしてノード上のディスク (emptyDir、サンドボックスと ともに削除) としてバックアップのデータの 2 倍に 512Mi を足したサイズ (最小 1Gi)。
設定 意味
CPU CPU リクエスト。CPU リミットはないため、復元はアイドル状態のコアを使えます
Memory メモリのリクエストとリミット
Disk データボリュームのサイズ。ストレージクラスを設定しない限りノードのディスク上
Storage class データはこのクラスの PVC に置かれます。ノードのディスクに収まらない大きな復元向け

チャートの sandbox.limits は CPU、メモリ、ディスクの上限を設定します。コンソールと API は上限を超えるリクエストを拒否し、 サイズが上限を超える復元 (ターゲットの設定、または大きなバックアップの自動サイズ) は、途中でディスクを埋めるのではなく理由を 示して失敗します。実行中のサンドボックスのサイズは変わりません。変更するには再度復元してください。

クラスター内から接続する

サンドボックスのホスト、ポート、認証情報は、そのページ (認証情報を表示、監査対象) と tenax sandbox show で確認できます。 他の Namespace の Pod には tenax.run/sandbox-client: <sandbox> ラベルが必要です。サンドボックスの ネットワークポリシーはそれ以外をすべて拒否します。

クラスター外から接続する

ノート PC からサンドボックスにどう到達するかは、インストール時の選択です (expose.provider、後述)。どの場合も次のとおりです。

  • サンドボックスのページの 外部アクセスを開く、tenax sandbox expose <sandbox>、または復元時の open external access (tenax restore … --expose) で外部アクセスを 開きます。operator ロールが必要です。
  • tenax sandbox connect <sandbox> で 接続します。任意のデータベースクライアント用の接続文字列が表示されます。 サンドボックスのページからコピーすることもできます。
  • 外部アクセスを閉じる または tenax sandbox unexpose <sandbox> で 閉じます。サンドボックスの期限切れや削除でも閉じられます。
expose.provider tenax sandbox connect の動作 クライアントに必要なもの
none (デフォルト) kubeconfig を通してローカルポートをサンドボックスに転送します (Ctrl+C まで) tenax-sbx-<sandbox> で port-forward が許可された kubeconfig
service サンドボックス自身のアドレスを表示します (postgres://…@sbx-7f3a.db.example.com:5432/app?sslmode=require) 不要: 任意のデータベースクライアントで TLS 接続
cloudflare Access ログイン後、ローカルポートで cloudflared access tcp を開きます (Ctrl+C まで) cloudflared と許可されたメールアドレス

Postgres のサンドボックスは独自の証明書で TLS を提供します (自己署名: クライアントは sslmode=require を使い、発行者を 確認せずに暗号化します)。MySQL のサンドボックスは MySQL が生成する証明書を使います。

クラスター外からサンドボックスに到達させる (管理者向け)

Tenax は自分では何も開きません。どの方式も、クラスターにすでにあるものを使います。

方式 service: サンドボックスごとの Kubernetes Service

公開された各サンドボックスには expose.service から作られる Service が付きます。クラスターで Service を処理しているものが アドレスを割り当て、Tenax はそのアドレスを表示します。開発者にとって最も簡単で (任意のデータベースクライアント)、どの Kubernetes でも動きます。

クラスターにあるもの 設定 開発者の接続先
クラウドのロードバランサー (AKS、EKS、GKE) type: LoadBalancer、sourceRanges: [<office or VPN CIDRs>] ロードバランサーの IP
上記に加えて external-dns さらに annotations: {external-dns.alpha.kubernetes.io/hostname: "sbx-{id}.db.example.com"} と hostnamePattern: "sbx-{id}.db.example.com" sbx-<id>.db.example.com
MetalLB (オンプレミス) type: LoadBalancer ネットワーク上のアドレス
Tailscale オペレーター loadBalancerClass: tailscale サンドボックスの tailnet 名。何も公開されません
上記のいずれもない type: NodePort、ノードに対応する名前を付けた hostnamePattern: "nodes.example.com" nodes.example.com:<node port>
expose:
  provider: service
  service:
    type: LoadBalancer
    sourceRanges: ["203.0.113.0/24"]   # who may connect; leave empty only on a private network

サンドボックスには本番データのコピーが入っています

パブリックなロードバランサーでは、サンドボックスを守るのはランダムなパスワード、TLS、時間制限だけです。 sourceRanges を開発者の接続元アドレスに設定するか、プライベートな方式 (Tailscale、クラウドのアノテーションによる 内部ロードバランサー、プライベートネットワーク上の MetalLB) を使ってください。

サンドボックスが公開されている間は、追加の NetworkPolicy がデータベースポートで expose.service.allowFrom を許可します (デフォルト: すべて。ロードバランサーのトラフィックはノードのアドレスから届くことが多いため、フィルタリングはロードバランサーの sourceRanges が担います)。k3s の組み込みロードバランサーでは、公開された各サンドボックスがノード上のデータベースポートを バインドするため、同時に公開できるのは Postgres と MySQL のサンドボックスそれぞれひとつだけです。

方式 cloudflare: Access ログインの背後のトンネル

トンネルには Cloudflare API トークンがひとつ 必要です。これはユーザーではなくインストールに属します。Tenax の Namespace にある Kubernetes Secret で、他の認証情報と同様に一度だけ設定します (GitOps のシークレットツール、たとえば SOPS を使って)。 コンソールはこのトークンを要求も保持も表示もしません。ゾーンの DNS と Access アプリケーションを変更できるトークンだからです。

  1. Cloudflare で My Profile → API Tokens → Create Token → Custom token を開き、ホスト名が属するゾーンに対して 次の権限を付けます。
    • Account: Cloudflare Tunnel: Edit
    • Account: Access: Apps and Policies: Edit
    • Zone: DNS: Edit
    • Zone: Zone: Read
  2. 保存します。

    kubectl -n tenax-system create secret generic tenax-cloudflare-api --from-file=token=api-token.txt
    
  3. チャートを設定します。

    expose:
      provider: cloudflare
      cloudflare:
        zone: example.com
        apiTokenSecret: tenax-cloudflare-api
        hostnamePattern: "sbx-{id}.example.com"
        allowEmails: ["*@example.com"]      # who may connect to an open tunnel
      cloudflared:
        enabled: true
    

ホスト名はゾーンの 1 階層下にしてください (sbx-{id}.db.example.com ではなく sbx-{id}.example.com)。Cloudflare の 無料証明書がカバーするのは *.example.com だけで、クライアントは HTTPS でホスト名に到達するからです。データベースのポートは ブラウザーのログインでは保護できないため、開発者は cloudflared を実行します。これは tenax sandbox connect が代わりに行います。

トークンがあれば、Tenax はゾーンからアカウントを見つけ、tenax という名前のトンネル (expose.cloudflare.tunnelName) を 作成または再利用し、トンネルのコネクタートークンを Secret <release>-tunnel-token に書き込みます。cloudflared Pod は この Secret から起動します。Tenax は 15 分ごとにこの Secret を確認するので、Cloudflare でローテーションされたトークンは 自動的に Secret に反映されます (反映するには cloudflared Pod を再起動します)。allowEmails にはアドレスとドメイン全体 (*@example.com) を、allowGroups には Access グループの ID を指定します。

すでに管理しているトンネルを使う

tenax の代わりに既存のリモート管理トンネルを使うには expose.cloudflare.tunnelID を設定します。コネクタートークンを 自分で用意したい場合は、それを保持する Secret (キー token) を expose.cloudflared.tunnelTokenSecret に設定します。 その場合 Tenax はその Secret に手を触れません。Tenax が追加・削除するのは自身の sbx-… ルールだけなので、トンネルの 他のルートはそのまま残ります。accountID と zoneID を設定すると検索を省略できます。

同じトンネルでコンソール自体を提供することもできます。Access アプリケーションの背後で tenax-api のパブリックホスト名を トンネルに追加し (Zero Trust → Networks → Tunnels → tenax → Public hostnames)、auth.provider: cloudflare-access とともに expose.cloudflared.consoleHostname を設定します。コンソール、CLI とアクセス を参照してください。