Cluster Settings
The cluster block decides what a Bridge container is and, for an orchestrator,
what it manages. A single-container deployment leaves the block alone. Every
setting below has a working default, so a clustered deployment sets only the
values that differ.
For the deployment steps that use these settings, see AWS ECS and Kubernetes.
The role a container runs
| Option | Type | Default | Description |
|---|---|---|---|
cluster.role | string | single | One of single, session, proxy, or orchestrator. Any other value stops startup. |
The four roles:
singleserves everything in one container: the web tier, the native listeners, and the sessions.proxyserves the web tier and the native listeners, and relays each session to a session worker.sessionserves one session, or a few, and then exits.orchestratorserves no traffic. It keeps the right number of session and proxy workers running.
The orchestrator does not proxy sessions, so a cluster needs at least one proxy
as well. Bridge reads this setting from BRIDGE_ROLE as well as from
BRIDGE_CLUSTER_ROLE, because the shorter name predates the naming scheme. See
Environment Variables.
Session worker limits
A session worker drains and exits when it reaches any one of these limits. The defaults give one session per container, which is the strongest isolation available: no two sessions ever share a process.
| Option | Type | Default | Description |
|---|---|---|---|
cluster.session.session_limit | int | 1 | Total sessions the worker serves before it drains and exits. 0 means no limit. |
cluster.session.max_concurrent_sessions | int | 1 | Sessions the worker serves at once before it stops accepting more. 0 means no limit. |
cluster.session.lifespan | duration | 0 | Drain and exit after this long, whatever the session count. 0 turns it off. |
Raising max_concurrent_sessions trades isolation for density. It is the setting
to change if warm workers cost more than the isolation is worth to you.
Proxy worker cycling
A proxy carries live connections, so it is replaced rather than restarted. The orchestrator starts a replacement, waits for it to become ready, retires the old one from the load balancer, waits for its relays to finish, and then terminates it.
| Option | Type | Default | Description |
|---|---|---|---|
cluster.proxy.lifespan | duration | 0 | Cycle a proxy once it is older than this. 0 turns cycling off. |
cluster.proxy.lifespan_jitter | duration | 0 | Spread the cycle time by plus or minus this much. 0 uses one sixth of lifespan. |
cluster.proxy.drain_deadline | duration | 0 | Longest a retiring proxy waits for its relays to finish. 0 waits indefinitely. |
cluster.proxy.max_cycle_concurrency | int | 1 | Proxies allowed to drain at the same time. 0 means no limit. |
The jitter is derived from the worker’s identity rather than drawn at random, so a given worker always cycles at the same offset. Without it a fleet started together retires together.
A drain_deadline of 0 is deliberate. An SSH or RDP session can outlast a
routine proxy cycle, and waiting is better than cutting the session off. Set a
deadline when you would rather bound the cycle than the session.
Orchestrator
| Option | Type | Default | Description |
|---|---|---|---|
cluster.orchestrator.warm_session_workers | int | 1 | Session workers kept ready to take a session. 0 leaves session workers unmanaged. |
cluster.orchestrator.proxy_workers | int | 1 | Proxy containers kept running. 0 leaves proxies unmanaged. |
cluster.orchestrator.reconcile | duration | 10s | How often the orchestrator compares what is running against what should be. |
cluster.orchestrator.lease | duration | 15s | Leader-election lease. Only the leader provisions, so a second orchestrator is a standby. |
Setting both warm_session_workers and proxy_workers to 0 stops the
reconcile loop entirely. The container still holds an election and reports
status, which is what you want before a provisioner is wired up.
Provisioner
The provisioner is how the orchestrator creates and destroys workers. It is a
script, and platform selects which sub-block carries the platform’s own values.
| Option | Type | Default | Description |
|---|---|---|---|
cluster.orchestrator.provisioner.platform | string | "" | k8s or ecs. Any other non-empty value stops startup. |
cluster.orchestrator.provisioner.path | string | "" | Path to the provisioner script. An empty path disables spawning. |
cluster.orchestrator.provisioner.k8s.image | string | "" | Image the orchestrator runs for a worker. The role arrives as BRIDGE_ROLE. |
cluster.orchestrator.provisioner.k8s.namespace | string | "" | Namespace workers are created in. It also bounds what the provisioner can touch. |
cluster.orchestrator.provisioner.ecs.task_definition | string | "" | Task-definition ARN the orchestrator runs for a worker. |
cluster.orchestrator.provisioner.ecs.cluster | string | "" | ECS cluster the tasks run in. It also bounds what the provisioner can touch. |
The two sub-blocks answer the same two questions per platform: what to run, and
where. Bridge reads only the sub-block that platform names, so values left in
the other one are ignored rather than merged.
Both deployment models ship a provisioner script in the image, and both the CloudFormation template and the Helm chart set these values for you. Set them by hand only when you supply your own script.
A configuration change does not reach a warm worker on Kubernetes. On ECS the
orchestrator compares the task definition each worker was created from, so a
changed setting cycles warm workers. The Kubernetes provisioner reports no
equivalent, so a warm worker there keeps its configuration until it cycles for
another reason: its own lifespan, or a session worker reaching its session
limit. Delete the pods to apply a change immediately.