Skip to content

Dynamic backend provisioning: spawn worlds on demand (Docker, then Kubernetes) #47

Description

@Pixnop

Correction to my original framing (thanks @jessica38 for pushing on it): I wrote that the registry already amounts to dynamic service discovery, and that is only half true. Checked against BackendRouter:

  • Initial joins are config-driven. The candidate pool comes from [servers] and the try order in nimbus.proxy.toml; the registry snapshot is used to filter that pool for health (stale, maintenance, capacity), never to add to it. A backend that heartbeats but is absent from the config is not a candidate for a player connecting to the proxy.
  • Transfers are registry-driven. /server <id>, /nimbus send and intents resolve the target from the registry snapshot, so those can reach a backend that only exists in the registry.

So the explicit Velocity-shaped model (a config file listing servers and a fallback order) is already the primary one, and it should stay that way. What this issue asks for is creating and destroying containers; it must be an opt-in layer on top of that model, not a replacement for it.

Proposal

  • A separate provisioner process (not a proxy plugin: cloud/orchestrator credentials stay out of the player-facing process), driving world templates declared in config: image or egg, variables, resource limits, savegame persistence policy.
  • Driver 1: Docker. Talks to the Docker socket; spawning a backend is exactly what the egg install already does, containerized. Smallest useful increment.
  • Driver 2: Kubernetes operator. A NimbusBackend CRD reconciled into StatefulSet + PVC per world. No k8s Services needed for discovery, heartbeats already do it.
  • Commands: nimctl spawn <template> [--name events-3] and nimctl despawn <server> = drain, evacuate (Evacuate: move every player off a backend in one command #41), then delete. Scale-down is only safe because those primitives exist.
  • Flagship use case: ephemeral event/minigame worlds that exist only while players are on them, later auto-scale rules (spawn when the hub queue grows, despawn when empty for N minutes).

Open questions: savegame lifecycle for ephemeral worlds (discard vs archive), secret distribution to spawned containers (inject at spawn, never bake into templates), who is allowed to spawn (admin socket permission model already has scopes), and how templates relate to the existing eggs (same install scripts, ideally).

Relates to #41 (evacuate is the safe-despawn primitive) and the panel eggs, which are effectively the manual version of a template.

Scale-to-zero: pause idle worlds

Nimbus has the exact signal needed: heartbeats carry player counts and the proxy sees every session, so "this world is empty" is known with certainty. Tiered lifecycle per template policy:

  1. Warm pause (docker pause / SIGSTOP) after N idle minutes: zero CPU, RAM kept, resume in milliseconds. A frozen process's listening socket still accepts connections into its backlog, so wake-on-connect is genuinely feasible: the proxy dials, the provisioner unfreezes, the connection completes.
  2. Cold stop (docker stop) after M idle hours: frees the RAM too (the real cost of a VS server); resume is 30-60s since worldgen already happened (the 2-4 min initial generation is paid once).
  3. Archive: container deleted, savegame kept. For finished event worlds.

Design point that needs care: a frozen backend stops heartbeating, so the registry would mark it stale and the proxy would refuse to route to it. This needs a provisioner-set Paused state in the registry, distinct from stale/dead, with "routable after wake" semantics: a route request toward a paused world triggers the wake, then routes, instead of rejecting.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions