콘텐츠로 이동

샌드박스와 쿼리

샌드박스는 백업이나 복원 가능 기간 안의 어떤 초에서든 복원한 전용 일회용 데이터베이스입니다. 들여다보는 일로 프로덕션이 위험해지는 일이 없으므로 기본 복원 위치입니다.

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

샌드박스란

  • 대상의 엔진과 버전(대상의 spec.sandbox.image)으로 된 데이터베이스 파드로, Tenax의 샌드박스 네임스페이스에서 생성된 자격 증명과 기본 거부 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)를 누르면 쿼리를 실행하며, 선택한 텍스트가 있으면 그 부분만 실행합니다. 자동 완성은 키워드, 함수, 테이블, 열을 제안합니다. 두 글자를 입력하면 열리고, alias. 뒤에서는 그 테이블의 열을, schema. 뒤에서는 그 스키마의 테이블을 나열하며, Ctrl+Space로 어디서든 열 수 있습니다. Tab 또는 Enter로 제안을 선택하고 Esc로 닫으며, 그 외에는 Tab이 들여쓰기를 합니다.

콘솔은 각 엔진의 SQL(현재 PostgreSQL과 MySQL)을 이해하며, 결과는 데이터베이스가 출력하는 그대로 값을 보여 줍니다.

크기 설정

각 샌드박스는 자체 네임스페이스의 데이터베이스 파드입니다. 할당되는 자원은 다음 중 먼저 설정된 곳에서 정해집니다.

  1. 복원: 복원 페이지의 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 제한, 그리고 노드에 백업 데이터의 두 배에 512Mi를 더한 디스크 (최소 1Gi, emptyDir이며 샌드박스와 함께 삭제됨)
설정 의미
CPU CPU 요청량. CPU 제한이 없으므로 복원 중 유휴 코어를 쓸 수 있음
메모리 메모리 요청량과 제한
디스크 데이터 볼륨 크기. 스토리지 클래스를 설정하지 않으면 노드 디스크에 저장
스토리지 클래스 노드 디스크로 감당할 수 없는 큰 복원을 위해 데이터를 이 클래스의 PVC에 저장

차트의 sandbox.limits는 CPU, 메모리, 디스크의 상한을 정합니다. 콘솔과 API는 상한을 넘는 요청을 거부하며, 크기가 상한을 넘게 계산되는 복원(대상의 설정이나 큰 백업의 자동 크기)은 디스크를 절반쯤 채운 뒤가 아니라 처음부터 사유와 함께 실패합니다. 실행 중인 샌드박스는 크기를 유지하므로, 바꾸려면 다시 복원하세요.

클러스터 내부에서 연결하기

샌드박스의 호스트, 포트, 자격 증명은 샌드박스 페이지(자격 증명 표시, 감사 로그에 기록)와 tenax sandbox show에 있습니다. 다른 네임스페이스의 파드에는 tenax.run/sandbox-client: <sandbox> 레이블이 필요하며, 샌드박스의 네트워크 정책은 그 밖의 모든 것을 거부합니다.

클러스터 외부에서 연결하기

노트북에서 샌드박스에 접근하는 방법은 설치 시 정합니다(expose.provider, 아래 참고). 어떤 경우든 다음과 같습니다.

  • 열기: 샌드박스 페이지의 외부 접근 열기, tenax sandbox expose <sandbox>, 또는 복원할 때 외부 접근 열기(tenax restore … --expose)로 외부 접근을 엽니다. operator 역할이 필요합니다.
  • 연결: tenax sandbox connect <sandbox>로 연결합니다. 모든 데이터베이스 클라이언트에서 쓸 수 있는 연결 문자열을 출력하며, 샌드박스 페이지에서 복사해도 됩니다.
  • 닫기: 외부 접근 닫기 또는 tenax sandbox unexpose <sandbox>로 닫습니다. 샌드박스가 만료되거나 삭제될 때도 닫힙니다.
expose.provider tenax sandbox connect의 동작 클라이언트에 필요한 것
none (기본값) Ctrl+C를 누를 때까지 kubeconfig를 통해 로컬 포트를 샌드박스로 포워딩 tenax-sbx-<sandbox>에서 포트 포워딩이 허용된 kubeconfig
service 샌드박스 자체의 주소를 출력 (postgres://…@sbx-7f3a.db.example.com:5432/app?sslmode=require) 없음: TLS로 연결하는 모든 데이터베이스 클라이언트
cloudflare Access 로그인 후 Ctrl+C를 누를 때까지 로컬 포트에서 cloudflared access tcp를 엶 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 네임스페이스의 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
    

호스트 이름은 존 바로 한 단계 아래로 두세요(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 파드는 이 Secret으로 시작합니다. Tenax는 이 Secret을 15분마다 확인하므로, Cloudflare에서 교체한 토큰은 자동으로 Secret에 반영됩니다(적용하려면 cloudflared 파드를 재시작하세요). allowEmails는 주소와 도메인 전체(*@example.com)를, allowGroups는 Access 그룹 ID를 받습니다.

이미 관리하고 있는 터널

tenax 대신 원격으로 관리되는 기존 터널을 쓰려면 expose.cloudflare.tunnelID를 설정하고, 커넥터 토큰을 직접 제공하고 싶다면 expose.cloudflared.tunnelTokenSecret에 그 토큰을 담은 Secret(키 token)을 지정하세요. 그러면 Tenax는 그 Secret을 건드리지 않습니다. Tenax는 자신의 sbx-… 규칙만 추가하고 제거하므로 터널의 다른 경로는 그대로 유지됩니다. accountID와 zoneID를 설정하면 조회를 건너뜁니다.

같은 터널로 콘솔 자체도 제공할 수 있습니다. Access 애플리케이션 뒤에 tenax-api용 공개 호스트 이름을 터널에 추가하고 (Zero Trust → Networks → Tunnels → tenax → Public hostnames), auth.provider: cloudflare-access와 함께 expose.cloudflared.consoleHostname을 설정하세요. 콘솔, CLI, 접근 권한을 참고하세요.