Skip to content
gameserver · agones · factorio

Managed dedicatedFactorio

A KBVE-baked Factorio dedicated-server image built to run as an Agones GameServer on the production Kubernetes cluster — a thin layer over the factoriotools rootless base with an in-tree scenario and a lifecycle shim.

Agones lifecycle shim

shim/agones-shim.sh execs the Factorio binary, seeds config defaults when no ConfigMap is mounted, drives Ready() plus a periodic Health() heartbeat, and traps SIGTERM so shutdowns get a clean autosave.

  • Rootless — runs as non-root UID 845.
  • Local-friendly — SDK skipped when AGONES_SDK_HTTP unset.
kbve/agones-factorioImage
factoriotools 2.0.76Base
AgonesOrchestration
KBVELicense

What it gives you

Features

Agones lifecycle shim

Ready() / periodic Health() and SIGTERM-driven autosave on shutdown.

KBVE scenario

An in-tree Lua soft-mod layer — joins, donor perks, chat commands — redmew-inspired but written fresh.

RCON + console-log

Loopback RCON and --console-log feed the planned chat-relay sidecar over a shared volume.

Rootless

Runs as non-root UID 845 so the GameServer PodSpec can require runAsNonRoot without a fight.

How it fits together

Overview

KBVE-baked Factorio dedicated-server image, designed to run as an Agones GameServer on the production Kubernetes cluster (issue #11138).

The image is a thin layer on top of factoriotools/factorio:2.0.76-rootless:

  • Lifecycle shimshim/agones-shim.sh execs the Factorio binary, copies bakeable defaults into /factorio/config/ only when a ConfigMap mount hasn’t already provided the file, drives Ready() + a periodic Health() heartbeat when AGONES_SDK_HTTP is set, and traps SIGTERM so Agones-initiated shutdowns get a clean autosave.
  • KBVE scenarioscenarios/kbve/ is our own Lua scenario, redmew-inspired but written fresh so we can grow the soft-mod layer in-tree (join/leave broadcasts, donor perks, chat commands).
  • RCON + console-log plumbing — when FACTORIO_RCON_PASSWORD is set the shim opens RCON bound to 127.0.0.1:27015 (loopback-only by default) and passes --console-log so the planned chat-relay sidecar can stream [CHAT]/[JOIN]/[LEAVE]/[COMMAND] markers off a shared emptyDir volume.
  • Rootless — UID 845 factorio, so the eventual GameServer PodSpec can require runAsNonRoot: true without a SecurityContext fight.

Roadmap

Phasing

PhaseScope
0Custom image + scenario + lifecycle shim (this entry)
1apps/kube/agones/factorio/ GameServer/Fleet + UDP exposure
2ConfigMap-driven server-settings.json + ExternalSecret for matchmaking token and RCON password
3Chat-relay sidecar (apps/agones/factorio/relay/, Rust) — log tail + RCON + IRC client; IRC → existing Discord bridge
4PVC + save-rotation CronJob + public download URL
5Observability — log shipping + RCON metrics + UPS / player-count alerts

Configuration

Container & runtime knobs

kbve/agones-factorio (local) / ghcr.io/kbve/agones-factorio (production), built via the standard nx container target:

Terminal window
./kbve.sh -nx agones-factorio:container
EnvDefaultNotes
FACTORIO_SCENARIOkbveScenario directory under /factorio/scenarios/
FACTORIO_PORT34197UDP listen port
FACTORIO_CONFIG_DIR/factorio/configMount a ConfigMap here in Phase 2
FACTORIO_CONSOLE_LOG/shared/log/console.logTailable by the Phase 3 relay sidecar
FACTORIO_RCON_PORT27015TCP, loopback-only by default
FACTORIO_RCON_BIND127.0.0.1RCON listen address
FACTORIO_RCON_PASSWORD(unset)When unset, RCON is not opened
AGONES_SDK_HTTP(unset)When unset, SDK calls are skipped — local docker run works without Agones
AGONES_READY_DELAY30Seconds before Ready()
AGONES_HEALTH_INTERVAL5Health() cadence

References — Issue #11138 (original planning ticket) · factoriotools/factorio (upstream rootless image) · Agones GameServer CRD.

Questions

Frequently asked

What is the Agones Factorio image?

A KBVE-baked Factorio dedicated-server OCI image built to run as an Agones GameServer on the production Kubernetes cluster, layered on the factoriotools rootless base.

How does the Agones lifecycle shim work?

The shim execs the Factorio binary, seeds config defaults when no ConfigMap is mounted, drives Ready() plus a periodic Health() heartbeat, and traps SIGTERM so shutdowns get a clean autosave.

Can the image run locally without Agones?

Yes. When AGONES_SDK_HTTP is unset the SDK calls are skipped, so a plain docker run works without an Agones controller.