Перейти к содержанию

Песочницы и запросы

Песочница — это приватная одноразовая база данных, восстановленная из резервной копии или на любую секунду окна. Это назначение восстановления по умолчанию, потому что просмотр данных никогда не должен угрожать продакшену.

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

Что такое песочница

  • Под базы данных с движком и версией цели (spec.sandbox.image в цели) в namespace песочниц Tenax, со сгенерированными учётными данными и NetworkPolicy, по умолчанию запрещающей всё.
  • TTL (sandbox.defaultTTL, не больше sandbox.maxTTL; оба задаются в политике и для всего чарта). Когда он истекает, Tenax удаляет песочницу и её хранилище. tenax sandbox extend <sandbox> --by 24h даёт больше времени; tenax sandbox delete <sandbox> завершает её досрочно.
  • Принадлежит тому, кто её запросил; каждое действие с ней записывается в аудит.

Запросы

Страница консоли Запрос и tenax query выполняют SQL через прокси запросов Tenax, по умолчанию только на чтение:

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 (Cmd+Enter на Mac) выполняет запрос или только выделенный текст, если что-то выделено. Автодополнение предлагает ключевые слова, функции, таблицы и столбцы: оно открывается после двух введённых символов, после alias. показывает столбцы этой таблицы, после schema. — её таблицы, а Ctrl+Space открывает его где угодно. Tab или Enter выбирает вариант, Esc закрывает список, а в остальных случаях Tab делает отступ.

Консоль понимает SQL каждого движка (сейчас PostgreSQL и MySQL); результаты показывают значения так, как их выводит база данных.

Размеры

Каждая песочница — это под базы данных в собственном namespace. Её ресурсы берутся из первого места, где они заданы:

  1. восстановление: поля CPU, Память, Диск и Storage class на странице восстановления (серым показаны значения, которые песочница получит, если оставить поля пустыми), tenax restore … --cpu 2 --memory 8Gi --size 50Gi --storage-class local-path или spec.destination.sandbox в Restore;
  2. цель: spec.sandbox.cpu, memory, sizeLimit, storageClass в BackupTarget;
  3. установка: sandbox.resources в чарте;
  4. встроенные значения: запрос 100m CPU и 256Mi памяти с лимитом 1Gi и диск вдвое больше данных резервной копии плюс 512Mi (не меньше 1Gi) на узле (emptyDir, удаляется вместе с песочницей).
Параметр Значение
CPU запрос CPU; лимита CPU нет, так что восстановление может использовать свободные ядра
Память запрос и лимит памяти
Диск размер тома данных; на диске узла, если не задан storage class
Storage class данные размещаются на PVC этого класса — для восстановлений больше, чем позволяют диски узлов

sandbox.limits в чарте задаёт потолки для CPU, памяти и диска. Консоль и API отклоняют запрос сверх них, а восстановление, размер которого получается больше (из настройки цели или автоматического размера большой резервной копии), завершается ошибкой с причиной, вместо того чтобы заполнить диск на полпути. Работающая песочница сохраняет свой размер: чтобы его изменить, восстановите заново.

Подключение из кластера

Хост, порт и учётные данные песочницы есть на её странице (Показать учётные данные, записывается в аудит) и в tenax sandbox show. Подам из других namespace нужна метка tenax.run/sandbox-client: <sandbox>; network policy песочницы отклоняет всё остальное.

Подключение извне кластера

Как к песочницам подключаются с ноутбука, решает установка (expose.provider, см. ниже). В любом случае:

  • Откройте внешний доступ кнопкой Открыть внешний доступ на странице песочницы, командой tenax sandbox expose <sandbox> или флажком открыть внешний доступ при восстановлении (tenax restore … --expose); нужна роль operator.
  • Подключитесь командой tenax sandbox connect <sandbox>, которая выводит строку подключения для любого клиента баз данных, или скопируйте её со страницы песочницы.
  • Закройте доступ кнопкой Закрыть внешний доступ или командой tenax sandbox unexpose <sandbox>. Он также закрывается, когда песочница истекает или удаляется.
expose.provider Что делает tenax sandbox connect Что нужно клиенту
none (по умолчанию) Пробрасывает локальный порт к песочнице через ваш kubeconfig до Ctrl+C kubeconfig с правом на port-forward в tenax-sbx-<sandbox>
service Выводит собственный адрес песочницы (postgres://…@sbx-7f3a.db.example.com:5432/app?sslmode=require) Ничего: любой клиент баз данных, по TLS
cloudflare После входа через Access открывает cloudflared access tcp на локальном порту до Ctrl+C cloudflared и разрешённый email

Песочницы Postgres обслуживают TLS с собственным сертификатом (самоподписанным: клиенты используют sslmode=require, что шифрует соединение без проверки издателя); песочницы MySQL используют сертификат, который генерирует MySQL.

Доступ к песочницам извне кластера (для администраторов)

Tenax сам ничего не открывает: каждый вариант использует то, что в вашем кластере уже есть.

Вариант service: Service Kubernetes на каждую песочницу

Каждая открытая песочница получает Service, построенный по expose.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 (on-premises) 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

Туннелям нужен один API-токен Cloudflare, который принадлежит установке, а не пользователю. Это Secret Kubernetes в namespace Tenax, который настраивается один раз, как любые другие учётные данные (вашими инструментами секретов для 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
    

Держите имена хостов на один уровень ниже зоны (sbx-{id}.example.com, а не sbx-{id}.db.example.com): бесплатный сертификат Cloudflare покрывает только *.example.com, а клиент обращается к имени хоста по HTTPS. Порт базы данных нельзя защитить входом через браузер, поэтому разработчики запускают cloudflared — это за них делает tenax sandbox connect.

С токеном Tenax находит аккаунт по зоне, создаёт туннель с именем tenax (expose.cloudflare.tunnelName) или использует существующий и записывает токен коннектора туннеля в Secret <release>-tunnel-token, с которым стартуют поды cloudflared. Этот Secret проверяется каждые 15 минут, так что токен, ротированный в Cloudflare, сам попадает в Secret (перезапустите поды cloudflared, чтобы они его подхватили). allowEmails принимает адреса и целые домены (*@example.com); allowGroups принимает id групп Access.

Туннель, которым вы уже управляете

Задайте expose.cloudflare.tunnelID, чтобы использовать существующий удалённо управляемый туннель вместо tenax, и expose.cloudflared.tunnelTokenSecret — Secret (ключ token) с его токеном коннектора, если хотите предоставлять его сами; тогда Tenax этот Secret не трогает. Tenax добавляет и удаляет только собственные правила sbx-…, так что остальные маршруты туннеля остаются как есть. Можно задать accountID и zoneID, чтобы пропустить поиск.

Тот же туннель может обслуживать и саму консоль: добавьте в туннель публичное имя хоста для tenax-api (Zero Trust → Networks → Tunnels → tenax → Public hostnames) за приложением Access и задайте expose.cloudflared.consoleHostname вместе с auth.provider: cloudflare-access: см. Консоль, CLI и доступ.