Skip to content

Workloads

A workload is one container image plus everything Brig needs to schedule it: replica count, resource ask, ports, volumes, env, secrets, placement rules, autoscaling, mesh policy, and snapshot policy. You describe it in a TOML file and brig deploy it.

name = "whoami"
image = "traefik/whoami:latest"
instances = 1
cpu = "100m"
memory = "32Mi"

That’s enough to deploy. brig deploy whoami.brig.toml parses, validates, schedules one replica on a healthy node, pulls the image, and gives the workload a public URL.

FieldRequiredDescription
nameyes1–63 chars, [a-z0-9-], no leading/trailing -. Unique per workspace.
imageyesOCI image reference, e.g. ghcr.io/me/api:v13. (Local image if [deploy] source = "local" — see Build from local image.)
instancesyesReplica count, 1–100. Brig keeps this many running across the fleet.
cpunoCPU ask. "500m" = 0.5 vCPU, or "1.5" = 1500m.
memorynoMemory ask. "512Mi", "1Gi", or raw "1024" (MiB). Binary units only — no decimal M/G.
commandnoOverride the image’s CMD.
portsnoPublished ports. See Network exposure.
envnoInline environment variables (map). Keys are POSIX-shaped ([A-Za-z_][A-Za-z0-9_]*).
secretsnoNames of workspace secrets to inject as env vars. See Secrets.
publicnotrue (default) gives a managed *.brig.run URL + TLS. false keeps the workload mesh-internal (bring your own ingress).
[[volume]]
mount = "/var/lib/data"

A bare [[volume]] with just a mount is a local volume — a node-pinned Docker named volume, one per replica, persisted across restarts on the same node. For a cloud block device that survives node loss, set class = "ebs" and a size:

[[volume]]
mount = "/var/lib/data"
class = "ebs"
size_gib = 20

Add a snapshot policy to drive recurring backups:

[[volume]]
mount = "/var/lib/data"
class = "ebs"
size_gib = 20
snapshot_every = "24h" # Go duration, minimum 1h
snapshot_keep = 7 # 1..365 most-recent retained
snapshot_destination = "prod" # name of a workspace destination; omit = default

See Volumes for the full lifecycle and Snapshots for backup/restore.

ports = ["80:whoami.example.com", "9000"]

Each entry is <container-port>[/<proto>][:<ingress-hostname>]:

  • "80" — expose container port 80 (TCP) inside the mesh only.
  • "80:api.example.com" — also route this hostname to it at the edge.
  • "9000/udp" — UDP port.

The Brig proxy mesh terminates TLS at the edge and routes to the nearest healthy replica. Replicas reach each other inside the mesh by workload name — no need to publish ports for internal traffic. See Networking for service discovery, custom domains, and mesh policy (allow_from / allow_to, sticky routing).

By default Brig spreads replicas across distinct nodes (anti-affinity). The [placement] block changes that:

[placement]
requires_labels = ["us-east", "ssd"] # only schedule on nodes with ALL these labels
node = "node-7" # hard-pin every replica to one node
together = true # co-locate all replicas on a single node
same_node_only = true # refuse cross-node inbound mesh calls
FieldDescription
requires_labelsScheduler considers only nodes carrying all of these labels. Set labels with brig node labels.
nodePin all replicas to one node by id.
togetherCo-locate all replicas on a single node instead of spreading them.
same_node_onlyThe mesh proxy returns 403 to any request that arrived from another node — defense-in-depth for sidecar databases.

Add an [autoscale] block to let Brig manage the replica count by CPU:

instances = 2 # must sit within [min, max]
[autoscale]
min = 2
max = 10
cpu_target = 0.70 # target average CPU utilisation (0..1); default 0.70
scale_up_after = "1m" # sustained breach before scaling up; default 1m
scale_down_after = "5m" # sustained slack before scaling down; default 5m

Autoscaling is on when min > 0 and max >= min. A controller sweeps roughly every 30s, computes average CPU across running replicas, and steps the count up or down by one, respecting the cooldown windows so it doesn’t flap. brig scale still works for a manual override within the band.

brig deploy is the same command for create and update. Brig diffs the new spec against the running version and rolls forward one replica at a time. Watch it inline with --watch, or check status separately:

Terminal window
brig deploy whoami.brig.toml --watch
brig status # one-screen fleet health
brig inspect whoami # per-replica detail + recent events

If a rollout gets stuck (image pull fail, health check red) Brig pauses and emits a RolloutStuck event (visible in brig inspect). Fix the underlying issue and run brig deploy again — the rollout resumes from where it stalled.

To revert to the previous version:

Terminal window
brig rollback whoami
Terminal window
brig scale whoami=5 # set instances to 5

This is purely a count change and does not bump the workload version. If you store the TOML in git, keep its instances (or [autoscale] band) in sync — the next brig deploy reconciles back to whatever the file says.

Every workload command takes --env to target a non-production environment. A bare name resolves to a sibling env file (--env staging.env.staging); an explicit path is used as-is (--env ./infra/.env.eu). Without --env, single-workload commands default to production; brig ps lists all envs. Environments are isolated in the mesh — a staging replica can’t reach a production one even if the workload names collide.

To ship an image built on your laptop without pushing to a registry, declare a local source and name the target node(s):

[deploy]
source = "local"
Terminal window
brig deploy api.brig.toml --node [email protected]

Brig docker saves the local tag, streams it over SSH to each --node, retags it brig-local/<workload>:<tag>-<digest>, and triggers a release. The agent recognises the brig-local/ prefix and skips the registry pull. You can also do this ad-hoc without a [deploy] block:

Terminal window
brig deploy --image api:v13 --workload api --node [email protected]

The complete TOML grammar — every field, type, and validation rule — lives in the CLI reference alongside the commands that consume it.