Piaskownice i zapytania¶
Piaskownica to prywatna, tymczasowa baza danych przywrócona z kopii zapasowej lub do dowolnej sekundy w oknie. To domyślne miejsce docelowe przywracania, bo przeglądanie danych nigdy nie zagraża produkcji.
tenax restore team-a/app --at 2026-10-07T09:41:27Z --ttl 6h --wait
tenax sandbox list
tenax sandbox show <sandbox>
Czym jest piaskownica¶
- Pod bazy danych z silnikiem i wersją celu (
spec.sandbox.imagew celu), w namespace piaskownic Tenax, z wygenerowanymi danymi uwierzytelniającymi i NetworkPolicy domyślnie blokującą ruch. - TTL (
sandbox.defaultTTL, najwyżejsandbox.maxTTL, oba w polityce i dla całego chartu). Gdy wygaśnie, Tenax usuwa piaskownicę i jej storage.tenax sandbox extend <sandbox> --by 24hdaje więcej czasu;tenax sandbox delete <sandbox>kończy ją wcześniej. - Należy do tego, kto o nią poprosił; każda akcja na niej jest rejestrowana w audycie.
Zapytania¶
Strona Zapytanie w konsoli i tenax query wykonują SQL przez proxy zapytań Tenax, domyślnie tylko do odczytu:
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
Każde zapytanie ma limit 30 sekund i zwraca najwyżej 1000 wierszy; --write pozwala na zapis (tylko piaskownice).
W edytorze Ctrl+Enter (Cmd+Enter na Macu) uruchamia zapytanie lub tylko zaznaczony tekst, jeśli jest
zaznaczenie. Uzupełnianie podpowiada słowa kluczowe, funkcje, tabele i kolumny: otwiera się po wpisaniu dwóch znaków,
po alias. pokazuje kolumny tej tabeli, po schema. jej tabele, a Ctrl+Space otwiera je w dowolnym miejscu.
Tab lub Enter wybiera podpowiedź, Esc ją zamyka, a w pozostałych przypadkach Tab wstawia wcięcie.
Konsola obsługuje dialekt SQL każdego silnika (dziś PostgreSQL i MySQL); wyniki pokazują wartości tak, jak wypisuje je baza danych.
Wymiarowanie¶
Każda piaskownica to pod bazy danych we własnym namespace. Co dostaje, według pierwszego miejsca, które to ustawia:
- przywracanie: pola CPU, Pamięć, Dysk i Klasa storage na stronie przywracania (wyszarzone wartości
to to, co dostanie, jeśli zostawisz je puste),
tenax restore … --cpu 2 --memory 8Gi --size 50Gi --storage-class local-pathlubspec.destination.sandboxw Restore; - cel:
spec.sandbox.cpu,memory,sizeLimit,storageClassw BackupTarget; - instalacja:
sandbox.resourcesw chartcie; - wbudowane: request 100m CPU i 256Mi pamięci z limitem 1Gi oraz dysk o rozmiarze dwukrotności danych kopii
zapasowej plus 512Mi (co najmniej 1Gi) na węźle (
emptyDir, usuwany razem z piaskownicą).
| Ustawienie | Znaczenie |
|---|---|
| CPU | request CPU; bez limitu CPU, więc przywracanie może używać wolnych rdzeni |
| Pamięć | request i limit pamięci |
| Dysk | rozmiar woluminu danych; na dysku węzła, chyba że ustawiono klasę storage |
| Klasa storage | dane trafiają wtedy na PVC tej klasy, dla przywracań większych, niż pozwalają dyski węzłów |
sandbox.limits w chartcie ustawia górne limity dla CPU, pamięci i dysku. Konsola i API odrzucają żądanie powyżej
nich, a przywracanie, którego rozmiar wychodzi powyżej (ustawienie celu lub automatyczny rozmiar dużej kopii
zapasowej), kończy się niepowodzeniem z podaniem powodu, zamiast zapełnić dysk w połowie. Działająca piaskownica
zachowuje swój rozmiar: aby go zmienić, przywróć ponownie.
Łączenie z klastra¶
Host, port i dane uwierzytelniające piaskownicy są na jej stronie (Pokaż dane uwierzytelniające, rejestrowane
w audycie) i w tenax sandbox show. Pody w innych namespace'ach potrzebują etykiety
tenax.run/sandbox-client: <sandbox>; polityka sieciowa piaskownicy odrzuca wszystko inne.
Łączenie spoza klastra¶
Sposób dostępu do piaskownic z laptopa wybiera instalacja (expose.provider, poniżej). W każdym przypadku:
- Otwórz dostęp zewnętrzny przyciskiem Otwórz dostęp zewnętrzny na stronie piaskownicy, poleceniem
tenax sandbox expose <sandbox>lub opcją otwórz dostęp zewnętrzny podczas przywracania (tenax restore … --expose); wymaga to rolioperator. - Połącz się przez
tenax sandbox connect <sandbox>, które wypisuje connection string dla dowolnego klienta bazy danych, albo skopiuj go ze strony piaskownicy. - Zamknij go przyciskiem Zamknij dostęp zewnętrzny lub przez
tenax sandbox unexpose <sandbox>. Zamyka się też, gdy piaskownica wygaśnie lub zostanie usunięta.
expose.provider |
Co robi tenax sandbox connect |
Czego potrzebuje klient |
|---|---|---|
none (domyślnie) |
Przekierowuje lokalny port do piaskownicy przez Twój kubeconfig, do Ctrl+C | kubeconfig z uprawnieniem do port-forward w tenax-sbx-<sandbox> |
service |
Wypisuje własny adres piaskownicy (postgres://…@sbx-7f3a.db.example.com:5432/app?sslmode=require) |
Niczego: dowolny klient bazy danych, przez TLS |
cloudflare |
Otwiera cloudflared access tcp na lokalnym porcie po zalogowaniu do Access, do Ctrl+C |
cloudflared i dozwolony adres e-mail |
Piaskownice Postgres udostępniają TLS z własnym certyfikatem (samopodpisanym: klienci używają sslmode=require, co
szyfruje bez sprawdzania wystawcy); piaskownice MySQL używają certyfikatu generowanego przez MySQL.
Dostęp do piaskownic spoza klastra (administratorzy)¶
Tenax sam niczego nie otwiera: każda opcja korzysta z czegoś, co Twój klaster już ma.
Opcja service: Service Kubernetes dla każdej piaskownicy¶
Każda udostępniona piaskownica dostaje Service zbudowany z expose.service; to, co w Twoim klastrze obsługuje
Service'y, nadaje mu adres, a Tenax ten adres pokazuje. To najprostsze rozwiązanie dla deweloperów (dowolny klient
bazy danych) i działa z każdym Kubernetes:
| Twój klaster ma | Ustaw | Deweloperzy łączą się z |
|---|---|---|
| Chmurowy load balancer (AKS, EKS, GKE) | type: LoadBalancer, sourceRanges: [<office or VPN CIDRs>] |
IP load balancera |
| To samo plus external-dns | dodatkowo annotations: {external-dns.alpha.kubernetes.io/hostname: "sbx-{id}.db.example.com"} i hostnamePattern: "sbx-{id}.db.example.com" |
sbx-<id>.db.example.com |
| MetalLB (on-premises) | type: LoadBalancer |
Adres w Twojej sieci |
| Operator Tailscale | loadBalancerClass: tailscale |
Nazwa piaskownicy w tailnecie; nic nie jest publiczne |
| Nic z powyższych | type: NodePort, hostnamePattern: "nodes.example.com" z pasującą nazwą dla Twoich węzłów |
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
Piaskownice zawierają kopie danych produkcyjnych
Publiczny load balancer chroni piaskownicę tylko jej losowym hasłem, TLS i limitem czasu. Ustaw sourceRanges
na adresy, z których łączą się Twoi deweloperzy, lub użyj opcji prywatnej (Tailscale, wewnętrzny load balancer
przez adnotację Twojej chmury, MetalLB w sieci prywatnej).
Gdy piaskownica jest udostępniona, dodatkowa NetworkPolicy wpuszcza expose.service.allowFrom (domyślnie: wszystko;
filtrowanie robi sourceRanges load balancera, bo jego ruch często przychodzi z adresów węzłów) na porcie bazy
danych. Na wbudowanym load balancerze k3s każda udostępniona piaskownica zajmuje port bazy danych na węzłach, więc
można tam jednocześnie udostępnić tylko jedną piaskownicę Postgres i jedną MySQL.
Opcja cloudflare: tunel za logowaniem Access¶
Tunele wymagają jednego tokenu API Cloudflare, który należy do instalacji, a nie do użytkownika. To Secret Kubernetes w namespace Tenax, konfigurowany raz jak każde inne dane uwierzytelniające (za pomocą narzędzi GitOps do sekretów, na przykład SOPS). Konsola nigdy o niego nie prosi, nie przechowuje go ani nie pokazuje: może on zmieniać DNS i aplikacje Access w strefie.
- W Cloudflare: My Profile → API Tokens → Create Token → Custom token z tymi uprawnieniami, dla strefy, w której
są nazwy hostów:
- Account: Cloudflare Tunnel: Edit
- Account: Access: Apps and Policies: Edit
- Zone: DNS: Edit
- Zone: Zone: Read
-
Zapisz go:
-
Skonfiguruj chart:
Trzymaj nazwy hostów jeden poziom pod strefą (sbx-{id}.example.com, nie sbx-{id}.db.example.com): darmowy
certyfikat Cloudflare obejmuje tylko *.example.com, a klient łączy się z nazwą hosta przez HTTPS. Portu bazy danych
nie da się chronić logowaniem w przeglądarce, więc deweloperzy uruchamiają cloudflared, co tenax sandbox connect
robi za nich.
Mając token, Tenax znajduje konto na podstawie strefy, tworzy tunel o nazwie tenax (expose.cloudflare.tunnelName)
lub używa istniejącego i zapisuje token konektora tunelu w Secret <release>-tunnel-token, z którego startują pody
cloudflared. Sprawdza ten Secret co 15 minut, więc token zrotowany w Cloudflare sam trafia do Secret (zrestartuj
pody cloudflared, aby go wczytały). allowEmails przyjmuje adresy i całe domeny (*@example.com); allowGroups
przyjmuje ID grup Access.
Tunel, którym już zarządzasz
Ustaw expose.cloudflare.tunnelID, aby użyć istniejącego, zdalnie zarządzanego tunelu zamiast tenax, oraz
expose.cloudflared.tunnelTokenSecret na Secret (klucz token) z jego tokenem konektora, jeśli wolisz dostarczyć
go sam; Tenax nie rusza wtedy tego Secret. Tenax dodaje i usuwa tylko własne reguły sbx-…, więc pozostałe trasy
tunelu zostają bez zmian. Można ustawić accountID i zoneID, aby pominąć ich wyszukiwanie.
Ten sam tunel może też obsługiwać samą konsolę: dodaj do tunelu publiczną nazwę hosta dla tenax-api (Zero Trust →
Networks → Tunnels → tenax → Public hostnames) za aplikacją Access i ustaw
expose.cloudflared.consoleHostname z auth.provider: cloudflare-access: zobacz Konsola, CLI i dostęp.