Sandboxes und Abfragen¶
Eine Sandbox ist eine private Wegwerf-Datenbank, wiederhergestellt aus einem Backup oder aus jeder Sekunde des Fensters. Sie ist das Standardziel einer Wiederherstellung, denn Nachsehen gefährdet nie die Produktion.
tenax restore team-a/app --at 2026-10-07T09:41:27Z --ttl 6h --wait
tenax sandbox list
tenax sandbox show <sandbox>
Was eine Sandbox ist¶
- Ein Datenbank-Pod mit Engine und Version des Ziels (
spec.sandbox.imageam Ziel), im Sandbox-Namespace von Tenax, mit generierten Zugangsdaten und einer NetworkPolicy, die standardmäßig alles verweigert. - Eine TTL (
sandbox.defaultTTL, höchstenssandbox.maxTTL, beides pro Policy und im ganzen Chart). Läuft sie ab, löscht Tenax die Sandbox und ihren Speicher.tenax sandbox extend <sandbox> --by 24hverschafft mehr Zeit;tenax sandbox delete <sandbox>beendet sie vorzeitig. - Sie gehört der Person, die sie angefordert hat; jede Aktion darauf wird protokolliert.
Abfragen¶
Die Seite Abfrage der Konsole und tenax query führen SQL über den Abfrage-Proxy von Tenax aus, standardmäßig
nur lesend:
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
Jede Abfrage hat ein Limit von 30 Sekunden und liefert höchstens 1.000 Zeilen; --write erlaubt Schreibzugriffe
(nur in Sandboxes).
Im Editor führt Ctrl+Enter (Cmd+Enter auf dem Mac) die Abfrage aus, bei einer Auswahl nur den markierten
Text. Die Vervollständigung bietet Schlüsselwörter, Funktionen, Tabellen und Spalten an: Beim Tippen öffnet sie sich
nach zwei Zeichen, nach alias. listet sie die Spalten dieser Tabelle, nach schema. deren Tabellen, und
Ctrl+Space öffnet sie überall. Tab oder Enter übernimmt einen Vorschlag, Esc schließt sie, und
sonst rückt Tab ein.
Die Konsole spricht das SQL jeder Engine (heute PostgreSQL und MySQL); Ergebnisse zeigen Werte so, wie die Datenbank sie ausgibt.
Dimensionierung¶
Jede Sandbox ist ein Datenbank-Pod in einem eigenen Namespace. Was sie bekommt, stammt von der ersten Stelle, die es festlegt:
- die Wiederherstellung: die Felder CPU, Speicher, Festplatte und Storage-Klasse auf der Seite Restore (die
ausgegrauten Werte gelten, wenn Sie sie leer lassen),
tenax restore … --cpu 2 --memory 8Gi --size 50Gi --storage-class local-pathoderspec.destination.sandboxeines Restore; - das Ziel:
spec.sandbox.cpu,memory,sizeLimit,storageClassdes BackupTarget; - die Installation:
sandbox.resourcesdes Charts; - eingebaut: 100m CPU, 256Mi angeforderter Speicher mit einem Limit von 1Gi und eine Disk von doppelter
Datengröße des Backups plus 512Mi (mindestens 1Gi) auf dem Node (
emptyDir, wird mit der Sandbox entfernt).
| Einstellung | Bedeutung |
|---|---|
| CPU | CPU-Request; kein CPU-Limit, damit eine Wiederherstellung freie Kerne nutzen kann |
| Memory | Speicher-Request und -Limit |
| Disk | Größe des Datenvolumes; auf der Disk des Nodes, sofern keine Storage Class gesetzt ist |
| Storage class | die Daten landen stattdessen auf einem PVC dieser Klasse, für Wiederherstellungen, die größer sind, als Node-Disks erlauben |
sandbox.limits im Chart setzt Obergrenzen für CPU, Speicher und Disk. Konsole und API lehnen eine Anfrage darüber
ab, und eine Wiederherstellung, deren Größe darüber liegt (durch eine Einstellung des Ziels oder die automatische
Größe eines großen Backups), schlägt mit Begründung fehl, statt mittendrin eine Disk zu füllen. Eine laufende
Sandbox behält ihre Größe: Stellen Sie erneut wieder her, um sie zu ändern.
Verbinden aus dem Cluster¶
Host, Port und Zugangsdaten der Sandbox stehen auf ihrer Seite (Zugangsdaten anzeigen, protokolliert) und in
tenax sandbox show. Pods in anderen Namespaces brauchen das Label tenax.run/sandbox-client: <sandbox>;
die Network Policy der Sandbox weist alles andere ab.
Verbinden von außerhalb des Clusters¶
Wie Sandboxes vom Laptop aus erreicht werden, entscheidet die Installation (expose.provider, siehe unten). In
jedem Fall gilt:
- Öffnen Sie den externen Zugriff mit Externen Zugriff öffnen auf der Seite der Sandbox,
tenax sandbox expose <sandbox>oder open external access beim Wiederherstellen (tenax restore … --expose); das braucht die Rolleoperator. - Verbinden Sie sich mit
tenax sandbox connect <sandbox>, das einen Connection-String für jeden Datenbank-Client ausgibt, oder kopieren Sie ihn von der Seite der Sandbox. - Schließen Sie ihn mit Externen Zugriff schließen oder
tenax sandbox unexpose <sandbox>. Er schließt sich auch, wenn die Sandbox abläuft oder gelöscht wird.
expose.provider |
Was tenax sandbox connect tut |
Der Client braucht |
|---|---|---|
none (Standard) |
Leitet einen lokalen Port über Ihre Kubeconfig an die Sandbox weiter, bis Strg+C | Eine Kubeconfig, die Port-Forwarding in tenax-sbx-<sandbox> erlaubt |
service |
Gibt die eigene Adresse der Sandbox aus (postgres://…@sbx-7f3a.db.example.com:5432/app?sslmode=require) |
Nichts: jeden Datenbank-Client, über TLS |
cloudflare |
Öffnet nach einem Access-Login cloudflared access tcp auf einem lokalen Port, bis Strg+C |
cloudflared und eine zugelassene E-Mail-Adresse |
Postgres-Sandboxes bieten TLS mit einem eigenen Zertifikat an (selbstsigniert: Clients verwenden
sslmode=require, das verschlüsselt, ohne den Aussteller zu prüfen); MySQL-Sandboxes verwenden das Zertifikat, das
MySQL erzeugt.
Sandboxes von außerhalb des Clusters erreichen (Administratoren)¶
Tenax öffnet von sich aus nichts: Jede Option nutzt etwas, das Ihr Cluster bereits hat.
Option service: ein Kubernetes-Service pro Sandbox¶
Jede freigegebene Sandbox erhält einen Service, gebaut aus expose.service; was auch immer Ihr Cluster für Services
betreibt, gibt ihm eine Adresse, und Tenax zeigt diese Adresse an. Für Entwickler ist das am einfachsten (jeder
Datenbank-Client) und funktioniert mit jedem Kubernetes:
| Ihr Cluster hat | Setzen Sie | Entwickler verbinden sich mit |
|---|---|---|
| Einen Cloud-Load-Balancer (AKS, EKS, GKE) | type: LoadBalancer, sourceRanges: [<office or VPN CIDRs>] |
Der IP des Load Balancers |
| Dasselbe, plus external-dns | zusätzlich annotations: {external-dns.alpha.kubernetes.io/hostname: "sbx-{id}.db.example.com"} und hostnamePattern: "sbx-{id}.db.example.com" |
sbx-<id>.db.example.com |
| MetalLB (On-Premises) | type: LoadBalancer |
Einer Adresse in Ihrem Netzwerk |
| Den Tailscale-Operator | loadBalancerClass: tailscale |
Dem Tailnet-Namen der Sandbox; nichts ist öffentlich |
| Nichts davon | type: NodePort, hostnamePattern: "nodes.example.com" mit einem passenden Namen für Ihre Nodes |
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
Sandboxes enthalten Kopien von Produktionsdaten
Ein öffentlicher Load Balancer schützt eine Sandbox nur mit ihrem Zufallspasswort, TLS und ihrem Zeitlimit.
Setzen Sie sourceRanges auf die Adressen, von denen Ihre Entwickler kommen, oder verwenden Sie eine private
Option (Tailscale, einen internen Load Balancer über die Annotation Ihrer Cloud, MetalLB in einem privaten
Netzwerk).
Solange eine Sandbox freigegeben ist, lässt eine zusätzliche NetworkPolicy expose.service.allowFrom (Standard:
alles; die Filterung übernimmt sourceRanges des Load Balancers, da dessen Traffic oft von Node-Adressen kommt)
auf den Datenbank-Port zu. Mit dem eingebauten Load Balancer von k3s belegt jede freigegebene Sandbox den
Datenbank-Port auf den Nodes, dort kann also jeweils nur eine Postgres- und eine MySQL-Sandbox freigegeben sein.
Option cloudflare: ein Tunnel hinter einem Access-Login¶
Tunnel brauchen ein Cloudflare-API-Token, das zur Installation gehört, nicht zu einem Benutzer. Es ist ein Kubernetes-Secret im Namespace von Tenax, einmal eingerichtet wie alle anderen Zugangsdaten (mit Ihrem GitOps-Secret-Werkzeug, zum Beispiel SOPS). Die Konsole fragt nie danach, speichert es nie und zeigt es nie an: Es kann DNS und Access-Anwendungen in der Zone ändern.
- In Cloudflare unter My Profile → API Tokens → Create Token → Custom token mit diesen Berechtigungen, für die
Zone, in der die Hostnamen liegen:
- Account: Cloudflare Tunnel: Edit
- Account: Access: Apps and Policies: Edit
- Zone: DNS: Edit
- Zone: Zone: Read
-
Speichern Sie es:
-
Konfigurieren Sie das Chart:
Halten Sie die Hostnamen eine Ebene unter der Zone (sbx-{id}.example.com, nicht sbx-{id}.db.example.com): Das
kostenlose Zertifikat von Cloudflare deckt nur *.example.com ab, und der Client erreicht den Hostnamen über HTTPS.
Ein Datenbank-Port lässt sich nicht durch einen Browser-Login schützen, daher führen Entwickler cloudflared aus,
was tenax sandbox connect für sie übernimmt.
Mit dem Token ermittelt Tenax das Konto aus der Zone, legt einen Tunnel namens tenax an
(expose.cloudflare.tunnelName) oder verwendet ihn wieder und schreibt das Connector-Token des Tunnels in das
Secret <release>-tunnel-token, aus dem die cloudflared-Pods starten. Es prüft dieses Secret alle 15 Minuten,
sodass ein in Cloudflare rotiertes Token von selbst im Secret ankommt (starten Sie die cloudflared-Pods neu, damit
sie es übernehmen). allowEmails nimmt Adressen und ganze Domains (*@example.com); allowGroups nimmt
Access-Gruppen-IDs.
Ein Tunnel, den Sie bereits verwalten
Setzen Sie expose.cloudflare.tunnelID, um statt tenax einen bestehenden, remote verwalteten Tunnel zu
verwenden, und expose.cloudflared.tunnelTokenSecret auf ein Secret (Schlüssel token) mit seinem
Connector-Token, wenn Sie es lieber selbst bereitstellen; Tenax lässt dieses Secret dann in Ruhe. Tenax fügt nur
seine eigenen sbx-…-Regeln hinzu und entfernt nur diese, die übrigen Routen des Tunnels bleiben also, wie sie
sind. accountID und zoneID lassen sich setzen, um die Nachschlagevorgänge zu überspringen.
Derselbe Tunnel kann auch die Konsole selbst bereitstellen: Fügen Sie dem Tunnel einen öffentlichen Hostnamen für
tenax-api hinzu (Zero Trust → Networks → Tunnels → tenax → Public hostnames), hinter einer Access-Anwendung,
und setzen Sie expose.cloudflared.consoleHostname mit auth.provider: cloudflare-access: siehe
Konsole, CLI und Zugriff.