Beachball

Quick start

Beachball needs three things: a scheduler, at least one host, and a client. Each step below is one command, and every value it needs has a default.

1. Start a scheduler

The scheduler runs on celld. Its only required setting is BEACHBALL_SECRET, a random value of at least 32 characters; every other secret derives from it.

For local development, from a checkout:

pnpm setup
pnpm dev

pnpm dev generates .dev/beachball/root.secret on first use, derives a bootstrap credential into .dev/beachball/local.token, and writes a bb profile that uses it. Run source .dev/beachball/environment.sh in each terminal that runs bb. The scheduler listens on http://127.0.0.1:8787 and runs on celld dev, which keeps its state in scheduler/.celld/dev; no Docker is needed. BEACHBALL_DEV_OBJECT_STORE=s3 runs a fleet node against a Docker Compose object store instead, the way production runs.

Without a deployment manifest, the scheduler is a single-tenant deployment in the default region with one default workload class. The bootstrap credential is both the administrator and the default client. See configuration to add tenants, classes, and limits.

2. Join a host

On the scheduler side, create a one-use join command for the new host:

bb --profile local-operator host enrollment-token create host-1
Run this on the new host before 2026-09-26T17:30:00Z (the token works once):
sudo bb agent join 'http://127.0.0.1:8787#bbe1.aG9zdC0x.…'

On the host (x86-64 Linux with KVM), run the printed command. bb agent join:

  • reads the region, network prefix, connection verification keys, and image settings from the scheduler's /v1/.well-known/beachball;
  • detects CPU, memory, and disk capacity (minus a reserve for the host), the uplink interface, and a free WireGuard UDP port;
  • enables the cgroup controllers and IPv4/IPv6 forwarding (persisted in /etc/sysctl.d/90-beachball.conf), and adds accept rules for Beachball's interfaces when a host firewall such as Docker or ufw drops forwarded traffic; bb agent run restores those rules after a reboot;
  • enrolls the host and runs every prerequisite check with a fix for each failure.

The host is active as soon as it joins; the scheduler places work on it after its first healthy heartbeat. Start the agent with the command join prints:

sudo bb agent run

Every detected value can be overridden; see bb agent setup --help.

3. Run a command

bb run ubuntu:26.04 -- uname -a

bb run creates an allocation, waits until the microVM is ready, and runs the command. The image is any container image reference (alpine:3.20, ghcr.io/org/app@sha256:…): the host pulls it and builds a bootable image the first time it sees it, which takes a minute, and reuses the build afterwards. Hosts build container images when they joined with --oci-kernel VMLINUX; a signed Beachball image reference (name@sha256:<digest>) works on every host. When the workload class has a default image, bb run -- uname -a is enough. Choose resources per request:

bb run --cpu-millis 2000 --memory-mib 4096 --script ./job.sh

Release the allocation when you are done:

bb allocation release ALLOCATION_ID

For a complete local Firecracker setup, including building and signing an Ubuntu image, run pnpm setup:firecracker; see run Beachball with Firecracker.

On this page