Skip to content

Configuration

Realm is configured through a YAML file. By default, Realm looks for a config.yaml file in the same directory as the executable. You can specify a custom path using the --config flag or the REALM_CONFIG_FILE environment variable.

A Realm configuration file has four top-level sections:

agent: # Agent settings
nodes: # Remote nodes to manage
loads: # Workloads to deploy
discovery: # Discovery settings
Field Type Default Description
data_path string /var/lib/realm Path to store client or agent data (ID file, database)
data_path: ./data

Nodes represent the machines where loads are deployed. Each node has a name (the map key), a URL pointing to its agent API, and a driver.

nodes:
lab1:
url: http://192.168.1.59:9000
driver: linux
lab2:
url: http://192.168.1.51:9000
driver: linux

url field can be also configured with a mDNS address:

nodes:
lab1:
url: http://lab1.local:9000
...
Field Type Required Description
url string Yes URL of the node’s agent API
driver string Yes Node driver type. Currently supported: linux
driver_config object No Driver-specific configuration
cloud_init object No Cloud init configuration
registries list No Container registries used by the node

Cloud init

Realm serves cloud-init configurations for any node with a cloud_init configuration. Currently Realm supports meta-dataand user-data structures.

An usage example using the VM node driver:

nodes:
vm:
url: http://localhost:9000
cloud_init:
meta_data:
instance-id: test01
local-hostname: testvm
user_data:
hostname: lab1
fqdn: lab1.local
preserve_hostname: false
apt:
sources:
bookworm-backports:
source: "deb http://deb.debian.org/debian bookworm-backports main contrib non-free-firmware"
runcmd:
- apt-get update
driver: vm
driver_config:
machine: q35
accel: hvf
memory: 2048
smp: "2"
serial: telnet:localhost:4444,server,nowait
netdev:
- type: user
id: net0
drives:
- file: /home/user/debian-12-generic-amd64.qcow2
format: qcow2
if: virtio

Container registries can be configured per node:

nodes:
lab1:
url: http://192.168.1.59:9000
driver: linux
registries:
- host: ghcr.io
auth:
token: ghp_xxxxxxxxxxxx
- host: registry.example.com:5000
insecure: true
auth:
username: admin
password: secret
- host: nexus.example.com
ca_file: /etc/realm/certs/nexus-ca.pem
auth:
username: admin
password: secret

insecure downgrades the connection to plain HTTP. For a registry that speaks HTTPS but presents a certificate Go refuses (for example one that relies on the legacy Common Name field instead of SANs), point ca_file at its CA bundle, or set skip_tls_verify: true to bypass verification altogether.

Field Type Description
host string Registry host (e.g., ghcr.io, docker.io)
insecure bool Allow HTTP instead of HTTPS
skip_tls_verify bool Do not verify the registry’s TLS certificate
ca_file string PEM bundle with extra CAs trusted for this registry
auth.username string Username (use with password)
auth.password string Password (use with username)
auth.token string Authentication token (alternative to username/password)

The linux driver runs on a host where Realm is installed as a agent. It supports optional Wake-On-LAN to power the host on remotely:

nodes:
server:
url: http://192.168.1.59:9000
driver: linux
driver_config:
wol: true
MAC: "00:11:22:33:44:55"
Field Type Description
wol bool Enable Wake-On-LAN
MAC string MAC address (required when wol is true)
nodes:
workstation:
url: http://192.168.1.20:9000
driver: windows
driver_config:
wol: true
MAC: "00:11:22:33:44:55"
Field Type Description
wol bool Enable Wake-On-LAN
MAC string MAC address (required when wol is true)

Experimental — Work in Progress

The VM driver is experimental and under active development. Its configuration schema, behavior, and defaults may change without notice, and it is not yet recommended for production use. Expect rough edges and please report issues you encounter.

The vm driver provisions guest nodes through a local libvirtd agent.

User running Realm must be allowed to run libvirt, set in /etc/libvirt/qemu.conf:

user = "<realm-user>"
group = "<realm-user>"

Now, restart libvirtd with sudo systemctl restart libvirtd so the overlay images under <data_path>/overlays/ are readable by the QEMU process.

nodes:
vm:
url: http://localhost:9000
driver: vm
driver_config:
machine: q35
accel: kvm
cpu: host
memory: 2048
smp: "2"
serial: telnet:localhost:4444,server,nowait
drives:
- file: https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2
format: qcow2
if: virtio
netdev:
- type: user
id: net0

The fields below describe a VM in driver-neutral terms; the driver translates them into a libvirt domain XML document. The emulator path is recorded as the <emulator> element, so libvirt invokes the binary you specify.

Field Type Required Description
machine string No Machine type (e.g. q35, pc). Mapped to <os><type machine=...>.
accel string or list No Accelerator selection. The first recognised entry (kvm, hvf, xen) chooses the libvirt domain type; otherwise qemu (TCG).
cpu string No CPU model (e.g. host). Mapped to <cpu mode='custom'><model>...</model></cpu>.
memory int No Memory in MiB. Mapped to <memory unit='MiB'>.
smp string No vCPU count. Either an integer ("2") or a cpus=N,... form; the leading integer is used.
serial string No Serial backend. stdio / pty produce a pty device; file:/path redirects to a file; none disables it.
drives list No Drive definitions, see below.
netdevs list No Netdev definitions, see below.
Field Type Description
file string Path to the disk image. If it begins with http:// or https:// the image is downloaded and cached under <data_path>/images/ (keyed by URL hash).
format string Image format (e.g. qcow2, raw).
if string Drive interface (e.g. virtio, ide).
media string Media type (e.g. disk, cdrom).
index string Drive index.

For each drive Realm copies the source image into a per-node overlay under <data_path>/overlays/<node>/<uuid> and points the libvirt <disk> at the copy, so the original image is never written to. Overlays are removed on deprovision.

Field Type Description
type string Netdev type (e.g. user, tap, bridge).
id string Netdev id (referenced by -device ...,netdev=<id>).
ifname string TAP interface name.
script string TAP up script.
downscript string TAP down script.
br string Bridge name (used by bridge type and for cloud-init host IP resolution).
helper string Bridge helper binary.
net string User-mode network range.
dhcpstart string First DHCP address for user-mode networking.
hostfwd string User-mode host port forwarding rule (e.g. tcp::2222-:22).

When the node has a cloud_init block, the guest’s cloud-init datasource fetches metadata from the Realm agent. The <host> is resolved as follows:

  1. If any non-user netdev is configured and its br interface has an IPv4 address, that address is used.
  2. Otherwise, the agent’s auto-detected IP is used.
  3. Otherwise, the configured agent.listen_address (if not 0.0.0.0) is used.
  4. Fallback: 10.0.2.2 (the QEMU user-mode gateway), which only works when the guest uses user-mode networking.

Per-VM logs are managed by libvirtd (typically under /var/log/libvirt/qemu/<node>.log). Inspect domain state with virsh list --all and virsh dominfo <node>.

Loads are the workloads deployed to nodes. Each load has a name (the map key), a target node, a driver (container or process), and driver-specific configuration.

loads:
web:
node: lab1
driver: container
driver_config:
image: docker.io/library/nginx:latest
my_service:
node: lab2
driver: process
driver_config:
start_cmd: node
start_args: "server.js"
stop_signal: SIGTERM
Field Type Required Description
node string Yes Target node name or expression
driver string Yes Load driver: container or process
driver_config object Yes Driver-specific configuration
depends_on list No List of load names this load depends on

For detailed driver configuration, see Container Driver and Process Driver.

Loads can declare dependencies on other loads using depends_on. Realm builds a dependency graph and ensures loads start and stop in the correct order. Circular dependencies are detected and rejected.

loads:
database:
node: lab1
driver: container
driver_config:
image: docker.io/library/postgres:15
api:
node: lab1
driver: container
driver_config:
image: docker.io/library/myapi:latest
depends_on:
- database

In this example, database will always start before api, and api will stop before database.

The node field supports expressions using expr-lang for dynamic node selection. The expression context provides:

  • nodes - array of all configured nodes
  • selectAny(slice) - randomly select one item from a slice
nodes:
vps-1:
url: http://vps1:9000
driver: linux
vps-2:
url: http://vps2:9000
driver: linux
loads:
web:
node: selectAny(filter(nodes, .Name startsWith "vps-"))
driver: container
driver_config:
image: docker.io/library/nginx:latest

The agent section configures the Realm agent. All fields are optional and have sensible defaults.

agent:
listen_address: 0.0.0.0
listen_port: 9000
log_format: text
log_level: info
Field Type Default Description
listen_address string 0.0.0.0 Address to bind the agent API
listen_port int 9000 Port to bind the agent API
listen_socket string Empty Additional unix socket to expose the agent API on. Disabled when empty
log_format string text Log output format: text or json
log_level string info Minimum log level: debug, info, warn or error. The LOG_LEVEL environment variable overrides it

Besides the TCP listener, the agent API can optionally be exposed on a unix socket:

agent:
listen_address: 0.0.0.0
listen_port: 9000
listen_socket: /run/realm/agent.sock
Field Type Default Description
containerd_sock string /run/containerd/containerd.sock Containerd socket path
containerd_namespace string realm Containerd namespace
cni_path string /usr/lib/cni Path to CNI plugins
volumes_pool string realm_volumes ZFS pool name for container volumes
zfs bool false Enable ZFS for volume management
Field Type Default Description
proxy_enabled bool false Enable the reverse proxy
local_caddy_url string localhost:2019 Local Caddy proxy URL
master_caddy_url string localhost:2019 Master Caddy proxy URL

Realm agents can expose artifacts when configured.

Field Type Default Description
artifacts ArtifactsRepository Empty Artifacts repository config

artifacts field expects the following attributes:

Field Type Default Description
auth_required bool false Endpoints available only for authed requests
raw_path string nil Point to a local directory with raw artifacts (nesting not allowed)

Realm stores agent state in an embedded bbolt database at <data_path>/realm.db. No configuration is required.

discovery:
mdns: true
Field Type Default Description
mdns bool false Enable mDNS discovery

All agent configuration fields can be set via environment variables using the REALM_ prefix. Nested fields use underscores as separators:

Terminal window
REALM_AGENT_LISTEN_ADDRESS=0.0.0.0
REALM_AGENT_LISTEN_PORT=9000
REALM_DATA_PATH=/opt/realm
REALM_AGENT_ETCD_MODE=client

Environment variables take priority over config file values but are overridden by command-line flags.

data_path: /opt/realm_data
agent:
listen_address: 0.0.0.0
zfs: false
nodes:
lab1:
url: http://192.168.1.59:9000
driver: linux
registries:
- host: ghcr.io
auth:
token: ghp_xxxxxxxxxxxx
lab2:
url: http://192.168.1.51:9000
driver: linux
loads:
database:
node: lab1
driver: container
driver_config:
image: docker.io/library/postgres:15
env:
- POSTGRES_PASSWORD=secret
network:
network: backend
dns: true
ip_masq: true
mount_volume:
- volume_mount_point: /var/lib/postgresql/data
api:
node: lab1
driver: container
driver_config:
image: ghcr.io/myorg/api:latest
env:
- DB_HOST=database.realm
network:
network: backend
dns: true
ip_masq: true
port_map:
- host_port: 8080
container_port: 3000
protocol: tcp
depends_on:
- database
monitoring:
node: lab2
driver: process
driver_config:
start_cmd: prometheus
start_args: "--config.file=/etc/prometheus/prometheus.yml"
working_dir: /opt/prometheus
stop_signal: SIGTERM
discovery:
mdns: true