Files
supaspin/templates/values.yaml.tpl
T
Igor K.andClaude Sonnet 5 cfbc4f1612 feat: supaspin, on-demand throwaway Supabase instances on microk8s
Adds a terminal app that creates, lists, shows and deletes numbered Supabase
instances on a single-node microk8s server, for testing and staging copies of
any app. Nothing in it is specific to one app.

- supaspin: single-file Python app (menu and commands: create, list, show,
  env, tunnel, delete, mail, setup). Instance N gets namespace supaspin-N,
  hostname slot N, Postgres on <LAN IP>:544N and Studio on <LAN IP>:300N.
  Lowest free number is reused; a refused create says why.
- Disk: fixed-size ext4 image files, loop-mounted from /etc/fstab. db 2 GB,
  storage 1 GB, functions/snippets/deno/pgsodium 256 MB each. imgproxy mounts
  the storage volume (the chart's own imgproxy volume cannot see uploads, so
  image resizing failed). Empty mount points are made read-only until mounted
  so a pod started early after a reboot cannot initialise a database there.
- Memory: limits 5.625 GiB, requests 1.875 GiB per instance, all 12 services.
  Half of a production setup, except analytics (768 MiB) and realtime
  (384 MiB), which were killed for running out of memory at half of it.
- Priority class supaspin-low (-100, never preempts) on every instance pod.
- Public HTTPS through the existing nginx ingress with Let's Encrypt. The
  Studio and pg-meta routes are cut out of the Kong gateway config by a
  post-renderer, which also pins the db and studio pods to fixed host ports.
- Certificates: delete keeps the TLS secret (with its cert-manager issuer
  annotations) in namespace supaspin-certs and create restores it, so
  create/delete cycles do not hit Let's Encrypt's 5-per-week limit.
- Secrets generated per instance: JWT secret, anon and service keys, Postgres
  and Studio passwords, realtime/meta/logflare keys. The rendered values file
  is removed after install; secrets are never written through kubectl apply.
- Instance .env (mode 600) with the usual Supabase variable names, plus an SSH
  tunnel command and DATABASE_URL help.
- Delete is idempotent and finds the real mounts instead of trusting a list,
  so half-created and older instances clean up completely. A failed create
  offers to run it.
- Mail settings: saved defaults changeable from the menu; create asks to use
  them or enter different ones for that instance.
- install.sh: installs the app; accepts a Gitea token or a local checkout
  because git.didgibot.com requires sign-in even for public repositories.
  uninstall.sh: removes the app and, after confirmation, every instance.
- tests: 30 unittest cases (numbering, ports, JWT signing, values, .env,
  fstab handling, post-renderer, certificate secret handling).
- README: install, first-run setup, menu, tunnel, troubleshooting, uninstall.

Pinned chart: supabase-community/supabase-kubernetes 0.8.0 (Postgres 17.6.1.136).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 23:02:40 +03:00

89 lines
3.3 KiB
Smarty

# Generic Helm values for one supaspin instance (upstream supabase-kubernetes chart).
# Every dollar-brace placeholder below (for example the ANON_KEY one) is replaced by supaspin
# with a quoted string before Helm sees this file.
# Memory limits, priority class and volume sizes are added by supaspin itself (see
# instance_values() in the supaspin script) so they stay in one place next to the caps.
secret:
jwt:
anonKey: ${ANON_KEY}
serviceKey: ${SERVICE_KEY}
secret: ${JWT_SECRET}
db:
password: ${DB_PASSWORD}
database: postgres
analytics:
publicAccessToken: ${LOGFLARE_PUBLIC}
privateAccessToken: ${LOGFLARE_PRIVATE}
dashboard:
username: ${DASHBOARD_USERNAME}
password: ${DASHBOARD_PASSWORD}
s3:
keyId: ${S3_KEY_ID}
accessKey: ${S3_ACCESS_KEY}
realtime:
secretKeyBase: ${REALTIME_SECRET_KEY_BASE}
dbEncKey: ${REALTIME_DB_ENC_KEY}
meta:
cryptoKey: ${META_CRYPTO_KEY}
smtp:
username: ${SMTP_USER}
password: ${SMTP_PASS}
deployment:
analytics:
enabled: true
vector:
enabled: true
environment:
auth:
- {name: API_EXTERNAL_URL, value: ${PUBLIC_URL}}
- {name: GOTRUE_API_HOST, value: "0.0.0.0"}
- {name: GOTRUE_API_PORT, value: "9999"}
- {name: GOTRUE_SITE_URL, value: ${PUBLIC_URL}}
- {name: GOTRUE_URI_ALLOW_LIST, value: "*"}
- {name: GOTRUE_DISABLE_SIGNUP, value: "false"}
- {name: GOTRUE_JWT_DEFAULT_GROUP_NAME, value: authenticated}
- {name: GOTRUE_JWT_ADMIN_ROLES, value: service_role}
- {name: GOTRUE_JWT_AUD, value: authenticated}
- {name: GOTRUE_JWT_EXP, value: "3600"}
- {name: GOTRUE_EXTERNAL_EMAIL_ENABLED, value: "true"}
- {name: GOTRUE_MAILER_AUTOCONFIRM, value: "true"}
- {name: GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED, value: "false"}
- {name: GOTRUE_SMTP_ADMIN_EMAIL, value: ${SMTP_ADMIN_EMAIL}}
- {name: GOTRUE_SMTP_HOST, value: ${SMTP_HOST}}
- {name: GOTRUE_SMTP_PORT, value: ${SMTP_PORT}}
- {name: GOTRUE_EXTERNAL_PHONE_ENABLED, value: "false"}
- {name: GOTRUE_SMS_AUTOCONFIRM, value: "false"}
- {name: GOTRUE_SMTP_SENDER_NAME, value: ${SMTP_SENDER_NAME}}
- {name: GOTRUE_MAILER_URLPATHS_INVITE, value: /auth/v1/verify}
- {name: GOTRUE_MAILER_URLPATHS_CONFIRMATION, value: /auth/v1/verify}
- {name: GOTRUE_MAILER_URLPATHS_RECOVERY, value: /auth/v1/verify}
- {name: GOTRUE_MAILER_URLPATHS_EMAIL_CHANGE, value: /auth/v1/verify}
studio:
- {name: HOSTNAME, value: "::"}
- {name: STUDIO_PORT, value: "3000"}
- {name: DEFAULT_ORGANIZATION_NAME, value: Default Organization}
- {name: DEFAULT_PROJECT_NAME, value: ${PROJECT_NAME}}
- {name: SUPABASE_PUBLIC_URL, value: ${PUBLIC_URL}}
- {name: NEXT_ANALYTICS_BACKEND_PROVIDER, value: postgres}
ingress:
enabled: true
className: ${INGRESS_CLASS}
annotations:
# The chart default rewrites every path to "/", which breaks all APIs; null removes it.
nginx.ingress.kubernetes.io/rewrite-target: null
nginx.ingress.kubernetes.io/proxy-body-size: 50m
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
cert-manager.io/cluster-issuer: ${CLUSTER_ISSUER}
tls:
- hosts: [${HOST}]
secretName: ${TLS_SECRET}
hosts:
- host: ${HOST}
paths:
- path: /
pathType: Prefix