Clusters
Run your app across many machines
A container cluster is member VMs on a private network behind a managed load balancer. Deploy one or more services into it, scale replicas, and roll out new versions one service at a time — Suble places, balances and heals the containers for you.
# 1 — create the cluster (3 member VMs + a managed load balancer + a private network)
suble cluster create shop --size BXS.s1 --replicas 3
# 2 — deploy a service into it (3 container copies, load-balanced, with a domain)
suble cluster service add shop web \
--image registry.suble.io/acme/web:1.4 --port 3000 --replicas 3 --domain app.example.com
# 3 — that's it. The LB now serves app.example.com across all three members.
suble cluster show shopQuickstart
Three steps from nothing to a load-balanced, multi-VM deployment. The same flow lives in the dashboard (Console → Clusters) and declaratively in suble.yml.
1
Create the cluster
A cluster is shared infrastructure: N member VMs on a private network, behind a managed load balancer. Pick a member plan and how many VMs — everything else is provisioned for you.
suble cluster create shop --size BXS.s1 --replicas 32
Deploy a service
A service is a container image + a replica count. Replicas are placed across the members and registered as load-balancer backends. Give it a domain and it's served with automatic TLS.
suble cluster service add shop web \
--image registry.suble.io/acme/web:1.4 \
--port 3000 --replicas 3 --domain app.example.com3
Ship updates
Re-deploy a single service and it rolls out one container at a time behind the LB — health-checked before it takes traffic. Other services in the cluster are untouched.
suble cluster service deploy shop web --image registry.suble.io/acme/web:1.5What a cluster is made of
Four managed pieces, provisioned together and torn down together. You work with services; Suble keeps the machines, the routing and the network in sync underneath.
Member VMs
Real, visible instances — you can open a console, read their metrics, and see them in your instances list. Every member runs the same plan; add up to 9. Your containers run here, as Docker containers managed by the cluster.
Managed load balancer
A dedicated Caddy + HAProxy load balancer (optionally an HA pair with a floating VIP) sits in front. It routes each service's domain to that service's containers and terminates TLS. Exposed services get https + automatic Let's Encrypt certificates.
HTTP or raw TCP
Give a service a domain and it's published as HTTP/HTTPS with automatic TLS. Or set its protocol to TCP and pick a port — the load balancer forwards raw TCP straight through to your containers (game servers, message brokers, databases, any non-HTTP protocol). TCP is passthrough: your app terminates its own TLS.
Services & replicas
One cluster runs many services (up to 20). Each service is an image with its own replica count (up to 9), spread round-robin across the members as individual containers — so two replicas of the same service can land on the same member on different ports, and the LB balances across all of them.
Private network
Members and the load balancer share a private VLAN. The LB reaches your containers over their private IPs — traffic between the edge and your app never leaves the internal network. Auto-created with the cluster, or point it at an existing one.
Locked-down members
Every member's public interface is firewalled to ping only — no public SSH, no exposed container ports. All traffic reaches your services through the load balancer over the private network, and members are managed from the dashboard console, so nothing needs to listen on the public IP. You can re-enable SSH on any individual member from its firewall settings if you need direct access.
Internet
│ https://app.example.com (TLS terminated at the LB)
▼
┌─────────────── Managed Load Balancer ───────────────┐
│ Caddy (L7 http/https + auto-TLS) · HAProxy (L4 tcp) │
└───────┬───────────────┬───────────────┬─────────────┘
│ private net │ │
▼ ▼ ▼
member-1 member-2 member-3 ← your member VMs
web:20000 web:20000 web:20000 ← service "web", 3 replicas
api:20001 api:20001 ← service "api", 2 replicasRoll out new versions safely
Deploying a service replaces its containers one at a time behind the load balancer, each health-checked before it takes traffic — the same rolling / canary / blue-green strategies as a single instance. A deploy only ever touches the one service you name, so other services keep serving.
# roll out one service — the rest of the cluster is untouched
suble cluster service deploy shop web --image registry.suble.io/acme/web:1.5
# or declaratively, per repo, in that repo's suble.yml:
name: web
service:
cluster: shop
image: registry.suble.io/acme/web:1.5
port: 3000
replicas: 3
domain: app.example.com
deploy:
strategy: rolling # rolling (default) | canary | blue-green | immediate
healthcheck:
type: http
path: /healthz
status: 200Scale & self-heal
Scale two independent dials: the number of member VMs (more capacity to place containers) and how many replicas each service runs (more copies behind the LB). Both are live operations — no downtime for the services already running.
# more member VMs (more room to place containers) — up to 9
suble cluster scale shop --replicas 5
# more copies of one service — up to 9, balanced by the LB
suble cluster service scale shop web --replicas 6Self-healing members
If a member VM stops being healthy, the cluster provisions a replacement and re-places the containers that were on it — automatically, without you intervening.
HA at the edge
Create the cluster with an HA load-balancer pair and a floating VIP so the ingress itself survives a node failure and fails over in seconds.
Many services, one cluster
A cluster can run up to 20 services. The per-repo model keeps them independent: each repository has its own suble.yml with a service: block naming the shared cluster, and its own CI/CD. Deploying one repo reconciles only that service — teams ship on their own cadence without stepping on each other.
# repo A — apps/web/suble.yml
name: web
service:
cluster: shop # the shared cluster
build: { dockerfile: Dockerfile } # built + pushed to your registry
port: 3000
replicas: 3
domain: app.example.com # https + auto-TLS via the LB# repo B — apps/api/suble.yml (its own pipeline, same cluster)
name: api
service:
cluster: shop
image: registry.suble.io/acme/api:2.1
port: 8080
replicas: 2
domain: api.example.comA service with no domain stays internal — reachable by the other services in the cluster but not exposed by the load balancer. Perfect for workers and internal APIs.
Pricing
A cluster costs the sum of its parts — all metered hourly and capped monthly, like everything else on Suble. No separate “cluster” fee.
Member VMs
Each member is billed exactly like a standalone instance — its plan's hourly rate, capped at the monthly price. Scale the member count up or down and the bill follows by the hour.
The load balancer
The managed LB is billed at its size's rate — doubled for an HA pair. Reuse an existing load balancer for the cluster and it isn't billed twice.
The private network
The cluster's private network is 50 DKK / month, metered hourly. Reuse an existing network and there's nothing extra to pay. Deleting the cluster releases everything it owns.
The dashboard shows the live monthly estimate as you size the cluster, and the cluster page breaks the running cost down by members, load balancer and network.
Reference
The CLI commands and the suble.yml fields that drive a cluster. See the full suble.yml reference for every field, and Container Registry for pushing the images you deploy.
CLI commands
Commands
suble cluster create <name> | --size --replicas --ha | Create the infrastructure: member VMs (--size plan, --replicas count) + a managed LB (--ha for an HA pair) + a private network. |
suble cluster ls / show <name> | read | List your clusters, or show one cluster's members, services, per-container placements, health and monthly cost. |
suble cluster scale <name> | --replicas N | Change the number of member VMs (1–9). Members are added or drained + removed; running services are re-balanced. |
suble cluster service add <cluster> <name> | --image/--build --port --replicas --domain | Add a service. --domain exposes it via the LB (https); omit to serve on the LB IP over http, or leave it internal. |
suble cluster service scale <cluster> <name> | --replicas N | Change how many container copies of that service run across the members (1–9). |
suble cluster service deploy <cluster> <name> | --image / --strategy | Roll a new image out for one service, one container at a time behind the LB. Never touches other services. |
suble cluster service rm <cluster> <name> | delete | Remove a service and its containers + LB routes. suble cluster rm <name> tears down the whole cluster. |
cluster: — the infrastructure
Fields
cluster.sizerequired | string | Member VM plan code (e.g. BXS.s1). Every member runs this plan. |
cluster.replicas | number | Number of member VMs (default 2, max 9). The service's own replicas decide how many container copies run across them. |
cluster.ha | boolean | Provision an HA load-balancer pair with a floating VIP instead of a single LB VM. Default false. |
cluster.network | string | Private network (name or uid) the members + LB share. Auto-created if omitted; point it at an existing one to reuse it. |
service: — a workload in the cluster
Fields
service.clusterrequired | string | Target cluster (name or uid). Bootstrapped from the optional clusterSize/clusterInstances/clusterHa fields if it doesn't exist yet. |
service.build | service.imagerequired | block | string | Build a local Dockerfile (pushed to your registry.suble.io namespace, pulled automatically) or run a prebuilt image. |
service.portrequired | number | Container port the service listens on. |
service.replicas | number | Container copies spread across the members (default 1, max 9). |
service.domain | string | Public hostname → served by the LB with https + auto-TLS. Omit to serve on the LB IP over http, or leave the service internal. |
service.env / cpus / memory | map / number / size | Environment variables (${VAR} expands from the environment) and per-container CPU/memory limits. |