Przejdź do treści

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.image w celu), w namespace piaskownic Tenax, z wygenerowanymi danymi uwierzytelniającymi i NetworkPolicy domyślnie blokującą ruch.
  • TTL (sandbox.defaultTTL, najwyżej sandbox.maxTTL, oba w polityce i dla całego chartu). Gdy wygaśnie, Tenax usuwa piaskownicę i jej storage. tenax sandbox extend <sandbox> --by 24h daje 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:

  1. 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-path lub spec.destination.sandbox w Restore;
  2. cel: spec.sandbox.cpu, memory, sizeLimit, storageClass w BackupTarget;
  3. instalacja: sandbox.resources w chartcie;
  4. 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 roli operator.
  • 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.

  1. 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
  2. Zapisz go:

    kubectl -n tenax-system create secret generic tenax-cloudflare-api --from-file=token=api-token.txt
    
  3. Skonfiguruj chart:

    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
    

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.