fix: give the vector log collector a 512 MiB memory limit

- vector reads the log files of every pod on the node, so its memory need follows the node's log volume. At
  256 MiB it was killed for running out of memory 122 times on instance 1 and used 89% on instance 2.
  The limit is now 512 MiB (request unchanged at 128 MiB) for new instances; the total limit per instance
  goes from 5.625 GiB to 5.875 GiB, requests stay at 1.875 GiB.
- README memory table and the test for the totals updated
- version 1.1.1 -> 1.1.2

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit was merged in pull request #4.
This commit is contained in:
Igor K.
2026-09-19 12:56:35 +03:00
co-authored by Claude Sonnet 5
parent 45b02a85af
commit b86863e6f0
4 changed files with 24 additions and 18 deletions
+11 -8
View File
@@ -1,6 +1,6 @@
# supaspin # supaspin
Version 1.1.1 Version 1.1.2
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.
@@ -17,7 +17,7 @@ endangering them. Nothing in it is specific to any one app.
| Postgres | `<LAN IP>:544N` (instance 1 → 5441, 2 → 5442, …), bound on the LAN address only | | Postgres | `<LAN IP>:544N` (instance 1 → 5441, 2 → 5442, …), bound on the LAN address only |
| 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 2 GB, storage 1 GB, every other volume 256 MB** |
| Memory | limits add up to **5.625 GiB** per instance, requests to 1.875 GiB (table below) | | Memory | limits add up to **5.875 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 |
| Uploads | stored in the instance's own storage image (no MinIO); deleted with the instance | | Uploads | stored in the instance's own storage image (no MinIO); deleted with the instance |
@@ -108,7 +108,7 @@ sudo supaspin push-env N TARGET [--port P] [--key FILE] [--dry-run] # see "Cop
sudo supaspin delete N [--yes] sudo supaspin delete N [--yes]
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.1.1" supaspin --version # prints "supaspin 1.1.2"
``` ```
### Connecting your app ### Connecting your app
@@ -215,12 +215,15 @@ run `supaspin delete N` to clean up.
| analytics | 128 MiB | 768 MiB | | analytics | 128 MiB | 768 MiB |
| kong | 128 MiB | 512 MiB | | kong | 128 MiB | 512 MiB |
| realtime | 128 MiB | 384 MiB | | realtime | 128 MiB | 384 MiB |
| auth, functions, imgproxy, meta, rest, storage, studio, vector | 128 MiB each | 256 MiB each | | vector | 128 MiB | 512 MiB |
| **Total** | **1.875 GiB** | **5.625 GiB** | | auth, functions, imgproxy, meta, rest, storage, studio | 128 MiB each | 256 MiB each |
| **Total** | **1.875 GiB** | **5.875 GiB** |
Most limits are half of what a production setup would use. Analytics and realtime are higher: at Most limits are half of what a production setup would use. Analytics, realtime and vector are higher:
half of production they were killed for running out of memory in a loop (measured on a fresh at half of production they were killed for running out of memory in a loop (measured on a fresh
instance: analytics peaks at 624 MiB, realtime at 280 MiB). Image resizing (imgproxy) reads the instance: analytics peaks at 624 MiB, realtime at 280 MiB). Vector is the log collector: it reads the
log files of every pod on the server, not only its own instance's, so its memory need follows the
server's total log volume; at 256 MiB it was killed in a loop on one instance and used 89% on another. Image resizing (imgproxy) reads the
uploads from the storage volume, so it has no image of its own. uploads from the storage volume, so it has no image of its own.
## Troubleshooting ## Troubleshooting
+1 -1
View File
@@ -1 +1 @@
1.1.1 1.1.2
+7 -5
View File
@@ -32,7 +32,7 @@ import tty
import yaml import yaml
VERSION = "1.1.1" VERSION = "1.1.2"
CONFIG_PATH = os.environ.get("SUPASPIN_CONFIG", "/etc/supaspin/config.yaml") CONFIG_PATH = os.environ.get("SUPASPIN_CONFIG", "/etc/supaspin/config.yaml")
STATE_DIR = os.environ.get("SUPASPIN_STATE", "/var/lib/supaspin") STATE_DIR = os.environ.get("SUPASPIN_STATE", "/var/lib/supaspin")
CHART_REPO = "https://supabase-community.github.io/supabase-kubernetes" CHART_REPO = "https://supabase-community.github.io/supabase-kubernetes"
@@ -53,12 +53,14 @@ VOLUMES = {"db": 2048, "storage": 1024, "functions": 256,
DB_OWNED = ("db", "pgsodium") DB_OWNED = ("db", "pgsodium")
DB_UID, DB_GID = 100, 101 DB_UID, DB_GID = 100, 101
# Memory per service: (request MiB, limit MiB). Half of maralago.ru production, except analytics # Memory per service: (request MiB, limit MiB). Half of maralago.ru production, except analytics,
# and realtime: at half of production they were killed for running out of memory in a loop # realtime and vector: at half of production they were killed for running out of memory in a loop
# (measured on a fresh instance: analytics peaks at 624 MiB, realtime at 280 MiB). # (measured on a fresh instance: analytics peaks at 624 MiB, realtime at 280 MiB; vector reads the log
# files of every pod on the node, not only its own instance's, and was killed at 256 MiB on 2026-09-19).
SERVICES = ["db", "analytics", "kong", "auth", "functions", "imgproxy", "meta", SERVICES = ["db", "analytics", "kong", "auth", "functions", "imgproxy", "meta",
"realtime", "rest", "storage", "studio", "vector"] "realtime", "rest", "storage", "studio", "vector"]
MEMORY = {"db": (512, 2048), "analytics": (128, 768), "kong": (128, 512), "realtime": (128, 384)} MEMORY = {"db": (512, 2048), "analytics": (128, 768), "kong": (128, 512), "realtime": (128, 384),
"vector": (128, 512)}
DEFAULT_MEMORY = (128, 256) DEFAULT_MEMORY = (128, 256)
DEFAULT_MAIL = {"host": "smtp.example.com", "port": 587, "user": "", "password": "", DEFAULT_MAIL = {"host": "smtp.example.com", "port": 587, "user": "", "password": "",
+5 -4
View File
@@ -90,13 +90,14 @@ class Values(unittest.TestCase):
def test_memory_caps_add_up(self): def test_memory_caps_add_up(self):
req, lim = sp.total_memory_mib() req, lim = sp.total_memory_mib()
# db 2048, analytics 768, kong 512, realtime 384, the other eight 256 each # db 2048, analytics 768, kong 512, realtime 384, vector 512, the other seven 256 each
self.assertEqual(lim, 2048 + 768 + 512 + 384 + 8 * 256) self.assertEqual(lim, 2048 + 768 + 512 + 384 + 512 + 7 * 256)
self.assertEqual(lim / 1024, 5.625) self.assertEqual(lim / 1024, 5.875)
self.assertEqual(req, 512 + 11 * 128) # 1.875 GiB self.assertEqual(req, 512 + 11 * 128) # 1.875 GiB
# analytics and realtime were killed for running out of memory at half of production # analytics, realtime and vector were killed for running out of memory at half of production
self.assertGreaterEqual(sp.MEMORY["analytics"][1], 768) self.assertGreaterEqual(sp.MEMORY["analytics"][1], 768)
self.assertGreaterEqual(sp.MEMORY["realtime"][1], 384) self.assertGreaterEqual(sp.MEMORY["realtime"][1], 384)
self.assertGreaterEqual(sp.MEMORY["vector"][1], 512)
self.assertEqual(req / 1024, 1.875) self.assertEqual(req / 1024, 1.875)
for svc in sp.SERVICES: for svc in sp.SERVICES:
self.assertEqual(self.v["deployment"][svc]["priorityClassName"], "supaspin-low") self.assertEqual(self.v["deployment"][svc]["priorityClassName"], "supaspin-low")