Cluster Autoscaling
Phase Г.4 of the GA roadmap: from CP, click Cluster → Add node → CP provisions a VM on Hetzner / DigitalOcean and the node auto-registers within ~3 minutes. No SSH, no copy-token-then-curl.
Walkthrough
- CP → Cluster → Add node.
- Provider — Hetzner / DigitalOcean (Fly.io / AWS later).
- Token — paste API token. Verifies on submit; stored encrypted in
cc_settings(sensitive prefixautoscale.); reusable for later provisions. - Region — dropdown of
ListRegions. - Plan — table of
ListPlanswith vCPU / RAM / Disk / monthly cost. - Hostname + SSH key — optional pre-existing SSH key in the provider for break-glass console access.
- Confirm — preview “We will create a
cax21VM innbg1for ~€8.21/mo. Provisioning will take ~3 min.” - Run — SSE-backed progress:
provisioning → bootstrapping → registering → ready. - Done — green check + “Open node detail” CTA.
How it works
CP → Provider.Provision(spec) — creates VM with cloud-init user-data
↓
(~30 s) — VM boots, cloud-init writes /etc/quazzar/registration.env
↓
install.sh --register=… — runs the standard installer + POSTs registration heartbeat
↓
Node.Register(token) — CP validates the one-time token + binds the node to the tenant
↓
ready — node visible in the Cluster pageCloud-init bundle:
#cloud-config
write_files:
- path: /etc/quazzar/registration.env
permissions: '0600'
owner: root:root
content: |
QUAZZAR_REGISTER_URL=https://cp.quazzar.cloud/cp/api/v1/cluster/register
QUAZZAR_REGISTER_TOKEN={one_time_token}
QUAZZAR_TENANT_ID={tenant_id}
runcmd:
- curl -fsSL https://get.quazzar.cloud/install | bash -s -- --unattended --register=/etc/quazzar/registration.envThe one-time token has a 30-min TTL; failed bootstraps after that auto-decommission the partial VM.
Idempotency
- Hetzner: native
Idempotency-Keyheader. - DigitalOcean:
quazzar-idempotency:<hash>tag on the droplet.
A retry of the same job_id never creates a second VM.
Pricing
The wizard shows monthly cost per plan during selection. Hetzner exposes prices via API; DO does not directly — we ship a hand-curated price table updated quarterly. Banner: “Prices indicative. Confirm with provider.”
Plans
| Tier | Cluster autoscaling |
|---|---|
| Free / Pro | ❌ |
| Team | ✅ (≤5 provisioned nodes) |
| Enterprise | ✅ unlimited |
License gates: cluster_autoscale (Team+), cluster_autoscale_node_cap (Team=5 / Enterprise=∞). Manually-registered nodes (install.sh run by hand) don’t count toward the cap.
Cost & safety
- Monthly budget per tenant via
autoscale.<tenant>.budget_centssetting; provisioning blocked above it. - Token scoping — Hetzner: Read & Write; DO:
droplet:create + droplet:read + droplet:deleteminimum. Docs walk operators through provider IAM. - Auto-decommission — failed bootstraps after 30 min auto-delete the partial VM.
API
GET /cp/api/v1/cluster/providers → list
POST /cp/api/v1/cluster/providers/{name}/verify { token }
GET /cp/api/v1/cluster/providers/{name}/regions ?token=…
GET /cp/api/v1/cluster/providers/{name}/plans ?token=…®ion=…
POST /cp/api/v1/cluster/nodes → 202 { job_id }
GET /cp/api/v1/cluster/jobs → list
GET /cp/api/v1/cluster/jobs/{id} → status + progress
POST /cp/api/v1/cluster/jobs/{id}/cancel → 204
DELETE /cp/api/v1/cluster/nodes/{id} → tear down + revoke
POST /cluster/register — public; one-time tokenAdmin-only. Provider tokens never returned to the frontend after creation.
Roadmap follow-ups
- С.4.b: Fly.io + AWS EC2 + GCP Compute adapters.
- Auto-scaling on metric thresholds.
- Multi-region cluster fabric.
- Bring-your-own-cluster (Vultr, Linode, etc) via a generic cloud-init mode.