Resource limits
Cap app memory so one container can't take down the box, and watch usage in real time.
On a single box, one runaway container can starve everything else — including the control plane. VAC's defense is per-app memory limits plus always-on visibility into what's consuming resources.
Per-app memory limits
Set a memory ceiling on an app from its settings. On the next deploy, VAC writes a Compose
override applying mem_limit to the app's containers, and Docker enforces it as a hard cgroup
limit.
- The limit is per container, not an aggregate across the app — so one bad service can't OOM the host.
- Leave it unset (or
0) for no limit. - Hitting the limit triggers a kernel OOM kill, which VAC detects and notifies you about — usually the cue to raise the limit.
VAC enforces memory limits. It does not set per-container CPU quotas — all containers share the host CPU. Keep that in mind when sizing the box for CPU-bound workloads.
The control plane keeps itself small
VAC's own footprint is bounded so your apps get the machine:
vac-apiruns with a soft Go memory target (GOMEMLIMIT, ~180 MiB) and a hard container ceiling (~256 MiB).vac-db(Postgres) is tuned conservatively —shared_buffers=32MB,work_mem=2MB,max_connections=50.
That's how the whole control plane idles under 200 MB RAM excluding the database.
Live resource monitoring
The dashboard streams usage in real time:
- Per-service CPU and memory, sampled from
docker stats(every couple of seconds, only while you're watching an app). - Host vitals — CPU, memory, disk, and aggregate request rate.
Per-service stats collectors are subscriber-gated — they only run while someone is looking, so monitoring costs nothing when the dashboard is closed.
Disk and log hygiene
VAC prunes automatically so disk doesn't creep:
- Runtime logs: ~7 days, capped per service.
- Deployment history: most recent 20 per app.
- Activity log: 30 days.
- Old built images are pruned, keeping a few recent ones per app for fast rollback.