|
|
@@ -1,6 +1,6 @@
|
|
|
|
# supaspin
|
|
|
|
# supaspin
|
|
|
|
|
|
|
|
|
|
|
|
Version 1.6.2
|
|
|
|
Version 1.6.4
|
|
|
|
|
|
|
|
|
|
|
|
Create, list, show and delete throwaway [Supabase](https://supabase.com) instances on a
|
|
|
|
Create, list, show and delete throwaway [Supabase](https://supabase.com) instances on a
|
|
|
|
single-node [microk8s](https://microk8s.io) server, from a terminal menu.
|
|
|
|
single-node [microk8s](https://microk8s.io) server, from a terminal menu.
|
|
|
@@ -16,7 +16,7 @@ endangering them. Nothing in it is specific to any one app.
|
|
|
|
| Web API | `https://<slot hostname>` (auth, rest, graphql, realtime, storage, functions); the certificate is from Let's Encrypt when that is enabled, otherwise self-signed |
|
|
|
|
| Web API | `https://<slot hostname>` (auth, rest, graphql, realtime, storage, functions); the certificate is from Let's Encrypt when that is enabled, otherwise self-signed |
|
|
|
|
| Postgres | `<LAN IP>:544N` (instance 1 → 5441, 2 → 5442, …); which addresses listen is set by **Port bind** |
|
|
|
|
| Postgres | `<LAN IP>:544N` (instance 1 → 5441, 2 → 5442, …); which addresses listen is set by **Port bind** |
|
|
|
|
| Studio (admin UI) | `http://<LAN IP>:300N` (3001, 3002, …), not on the public hostname |
|
|
|
|
| Studio (admin UI) | `http://<LAN IP>:300N` (3001, 3002, …), not on the public hostname |
|
|
|
|
| Disk | fixed-size ext4 image files, mounted at boot: **db 2 GB, storage 1 GB, every other volume 256 MB** |
|
|
|
|
| Disk | fixed-size ext4 image files, mounted at boot: **db 6 GB, storage 1 GB, every other volume 256 MB** |
|
|
|
|
| Memory | limits add up to **9 GiB** per instance, requests to 1.875 GiB (table below) |
|
|
|
|
| Memory | limits add up to **9 GiB** per instance, requests to 1.875 GiB (table below) |
|
|
|
|
| Priority | pods run at priority -100 (`supaspin-low`); when the server runs short of memory they are evicted first and never evict anyone else |
|
|
|
|
| Priority | pods run at priority -100 (`supaspin-low`); when the server runs short of memory they are evicted first and never evict anyone else |
|
|
|
|
| Secrets | generated fresh per instance: JWT secret, anon and service keys, Postgres password, Studio password, and the internal keys |
|
|
|
|
| Secrets | generated fresh per instance: JWT secret, anon and service keys, Postgres password, Studio password, and the internal keys |
|
|
|
@@ -33,7 +33,9 @@ of instances at once. Numbers are reused: create picks the lowest free one.
|
|
|
|
|
|
|
|
|
|
|
|
- A Debian/Ubuntu server with **microk8s** (or any Kubernetes with `kubectl` and `helm` on the
|
|
|
|
- A Debian/Ubuntu server with **microk8s** (or any Kubernetes with `kubectl` and `helm` on the
|
|
|
|
path), with an ingress controller installed: **ingress-nginx** or **Traefik** (the microk8s
|
|
|
|
path), with an ingress controller installed: **ingress-nginx** or **Traefik** (the microk8s
|
|
|
|
`ingress` addon is either, depending on the version).
|
|
|
|
`ingress` addon is either, depending on the version). With **Traefik**, its CRDs must be present
|
|
|
|
|
|
|
|
on the cluster — they come with the Traefik installation itself; supaspin creates `Middleware`
|
|
|
|
|
|
|
|
objects and does not install cluster-wide types.
|
|
|
|
- With **Let's Encrypt** enabled: **cert-manager** installed, DNS `A` records for every hostname
|
|
|
|
- With **Let's Encrypt** enabled: **cert-manager** installed, DNS `A` records for every hostname
|
|
|
|
slot pointing at the server, and ports 80 and 443 forwarded to it (Let's Encrypt fetches a test
|
|
|
|
slot pointing at the server, and ports 80 and 443 forwarded to it (Let's Encrypt fetches a test
|
|
|
|
file over port 80 to issue each certificate). Without it: no cert-manager, no public DNS — each
|
|
|
|
file over port 80 to issue each certificate). Without it: no cert-manager, no public DNS — each
|
|
|
@@ -77,7 +79,7 @@ sudo supaspin
|
|
|
|
| Server LAN IP | address shown for the Postgres and Studio ports (detected) |
|
|
|
|
| Server LAN IP | address shown for the Postgres and Studio ports (detected) |
|
|
|
|
| Port bind | `lan` = LAN IP only (default; keeps Postgres and the login-less Studio off a public interface), `all` = every interface incl. localhost (for a box behind NAT running its own apps), `local` = localhost only |
|
|
|
|
| Port bind | `lan` = LAN IP only (default; keeps Postgres and the login-less Studio off a public interface), `all` = every interface incl. localhost (for a box behind NAT running its own apps), `local` = localhost only |
|
|
|
|
| Ingress class | usually `public` on microk8s |
|
|
|
|
| Ingress class | usually `public` on microk8s |
|
|
|
|
| Ingress controller | `traefik` or `nginx`; Traefik instances get a Middleware that caps uploads at 50 MiB, nginx gets the equivalent annotations |
|
|
|
|
| Ingress controller | `traefik` or `nginx`; every instance's Ingress carries the nginx annotations (50 MiB upload cap, long timeouts) and, in Traefik mode, additionally points at a `Middleware` object with the same 50 MiB cap - so the cap is enforced no matter which of the two actually routes the hostname |
|
|
|
|
| Let's Encrypt | `y` fetches a real certificate per hostname (needs public DNS, ports 80/443, cert-manager); `n` gives every instance a self-signed certificate and creates no cert-manager objects |
|
|
|
|
| Let's Encrypt | `y` fetches a real certificate per hostname (needs public DNS, ports 80/443, cert-manager); `n` gives every instance a self-signed certificate and creates no cert-manager objects |
|
|
|
|
| Let's Encrypt e-mail | for certificate expiry notices (asked only when Let's Encrypt is on) |
|
|
|
|
| Let's Encrypt e-mail | for certificate expiry notices (asked only when Let's Encrypt is on) |
|
|
|
|
| Hostname slots | comma-separated; a name with a number in it keys that slot (`supa4.didgibot.com` = slot 4, so instance 4 gets it with ports 5444/3004), a plain name takes its position in the list |
|
|
|
|
| Hostname slots | comma-separated; a name with a number in it keys that slot (`supa4.didgibot.com` = slot 4, so instance 4 gets it with ports 5444/3004), a plain name takes its position in the list |
|
|
|
@@ -115,12 +117,12 @@ sudo supaspin env N # the full .env (contains secrets)
|
|
|
|
sudo supaspin tunnel N # the tunnel commands, step by step
|
|
|
|
sudo supaspin tunnel N # the tunnel commands, step by step
|
|
|
|
sudo supaspin push-env N TARGET [--port P] [--key FILE] [--dry-run] # see "Copying an instance's values"
|
|
|
|
sudo supaspin push-env N TARGET [--port P] [--key FILE] [--dry-run] # see "Copying an instance's values"
|
|
|
|
sudo supaspin delete N [--yes]
|
|
|
|
sudo supaspin delete N [--yes]
|
|
|
|
sudo supaspin upgrade [N] # apply this version's memory caps to running instances
|
|
|
|
sudo supaspin upgrade [N] # apply this version's memory caps and log retention to running instances
|
|
|
|
sudo supaspin suspend N # stop an instance, keep its data (see "Suspending an instance")
|
|
|
|
sudo supaspin suspend N # stop an instance, keep its data (see "Suspending an instance")
|
|
|
|
sudo supaspin resume N # start it again
|
|
|
|
sudo supaspin resume N # start it again
|
|
|
|
sudo supaspin mail # change the saved default mail settings
|
|
|
|
sudo supaspin mail # change the saved default mail settings
|
|
|
|
sudo supaspin setup # change settings
|
|
|
|
sudo supaspin setup # change settings
|
|
|
|
supaspin --version # prints "supaspin 1.3.1"
|
|
|
|
supaspin --version # prints "supaspin X.Y.Z"
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Connecting your app
|
|
|
|
### Connecting your app
|
|
|
@@ -300,7 +302,9 @@ every delivery with an error, and vector was killed against its 1024 MiB ceiling
|
|
|
|
minutes with the undeliverable backlog. The fix is log retention: every instance gets a pg_cron
|
|
|
|
minutes with the undeliverable backlog. The fix is log retention: every instance gets a pg_cron
|
|
|
|
job (set up on create, upgrade and resume) that deletes analytics logs older than **2 days** every
|
|
|
|
job (set up on create, upgrade and resume) that deletes analytics logs older than **2 days** every
|
|
|
|
night. pg_cron in this image only runs jobs from the `postgres` database, so the job lives there
|
|
|
|
night. pg_cron in this image only runs jobs from the `postgres` database, so the job lives there
|
|
|
|
and reaches the log tables in `_supabase` over a local dblink connection. That bounds both the
|
|
|
|
and reaches the log tables in `_supabase` over a local dblink connection. The dblink extension
|
|
|
|
|
|
|
|
and the helper function live in the `extensions` schema, where the app's database owner has no
|
|
|
|
|
|
|
|
rights, so instance code can never call them. That bounds both the
|
|
|
|
db image and vector's backlog, so vector is back to the 512 MiB ceiling the production supabase
|
|
|
|
db image and vector's backlog, so vector is back to the 512 MiB ceiling the production supabase
|
|
|
|
charts carry.
|
|
|
|
charts carry.
|
|
|
|
|
|
|
|
|
|
|
@@ -317,6 +321,9 @@ pods are replaced service by service and nothing else about the instance changes
|
|
|
|
- **Certificate stays pending.** The hostname's DNS record must point at the server and port 80 must
|
|
|
|
- **Certificate stays pending.** The hostname's DNS record must point at the server and port 80 must
|
|
|
|
reach the ingress: `kubectl get certificate,order,challenge -n supaspin-N`.
|
|
|
|
reach the ingress: `kubectl get certificate,order,challenge -n supaspin-N`.
|
|
|
|
- **"no free hostname slot".** Delete an instance or add a slot in Settings (and its DNS record).
|
|
|
|
- **"no free hostname slot".** Delete an instance or add a slot in Settings (and its DNS record).
|
|
|
|
|
|
|
|
- **Create failed** with `no matches for kind "Middleware" in version "traefik.io/v1alpha1"`. The
|
|
|
|
|
|
|
|
config says Traefik but the cluster has no Traefik CRDs: either install Traefik (its CRDs come
|
|
|
|
|
|
|
|
with it) or set the ingress controller to `nginx` in Settings.
|
|
|
|
- **Create failed.** `sudo supaspin delete N`, then create again.
|
|
|
|
- **Create failed.** `sudo supaspin delete N`, then create again.
|
|
|
|
- **Port already in use.** Postgres and Studio ports are fixed per number (`5440+N`, `3000+N`);
|
|
|
|
- **Port already in use.** Postgres and Studio ports are fixed per number (`5440+N`, `3000+N`);
|
|
|
|
another program is using it. Free the port or use another instance number.
|
|
|
|
another program is using it. Free the port or use another instance number.
|
|
|
|