Running runed
runed is one process. Run it under a supervisor, give it a stable data directory, and watch its logs. That’s the whole job.
Systemd (recommended)
Section titled “Systemd (recommended)”The official server install drops a unit at /etc/systemd/system/runed.service. If you installed manually, here’s a known-good unit:
[Unit]Description=Rune control planeAfter=network-online.target docker.serviceWants=network-online.target
[Service]Type=simpleExecStart=/usr/local/bin/runed --config /etc/rune/runefile.yamlRestart=on-failureRestartSec=2sLimitNOFILE=65536StateDirectory=runeUser=root# Or run as an unprivileged user with access to /var/lib/rune and the docker socket.
[Install]WantedBy=multi-user.targetLifecycle:
sudo systemctl daemon-reloadsudo systemctl enable --now runedsudo systemctl status runedsudo systemctl restart runedsudo journalctl -u runed -fData directory
Section titled “Data directory”--data-dir (default /var/lib/rune) holds:
- BadgerDB state (services, instances, secrets ciphertexts, tokens, policies).
- The KEK file, if
crypto.kek.source: file. - Per-resource version history.
Back this up. Loss = loss of every service spec, secret, user, and policy.
# Snapshotsudo systemctl stop runedsudo tar -czf rune-backup-$(date +%F).tgz -C /var/lib runesudo systemctl start runedFor online backup, use BadgerDB’s snapshot tooling or copy while accepting that some recent writes may be missed. Multi-node with Raft snapshots is roadmap (RUNE-029).
runed writes logs to stdout. Under systemd, that goes to journald:
journalctl -u runed -fjournalctl -u runed --since "1 hour ago"journalctl -u runed -p err # errors onlyConfigure verbosity in the runefile (server.log-level) or with --log-level. Use --log-format=json if you ship logs to a structured collector.
Signals
Section titled “Signals”| Signal | Behavior |
|---|---|
SIGTERM | Graceful shutdown — drains gRPC, stops orchestrator, exits. |
SIGINT | Same as SIGTERM. |
SIGHUP | Reserved (no-op today). |
Graceful shutdown waits for in-flight RPCs (with a timeout) and writes any pending state. Don’t SIGKILL unless something is wedged — you risk losing recent writes.
Listening addresses
Section titled “Listening addresses”server: grpc-addr: ":7863" # bind all interfaces http-addr: ":7861"In production, bind to a private interface and front-door with TLS. To restrict to localhost:
server: grpc-addr: "127.0.0.1:7863" http-addr: "127.0.0.1:7861"Resource sizing
Section titled “Resource sizing”For Release 1 (single node):
| Workload size | RAM | Disk | CPU |
|---|---|---|---|
| ≤ 20 services | 256 MiB | 1 GiB | 0.25 c |
| ≤ 100 services | 512 MiB | 5 GiB | 0.5 c |
| ≤ 500 services | 1 GiB | 20 GiB | 1 c |
These are rough. Disk grows with secret/configmap version history — set storage retention to taste.
Health endpoint
Section titled “Health endpoint”runed exposes a health endpoint at :7861/healthz. Use it for liveness from your host’s monitoring.
curl -fsS http://localhost:7861/healthzReturns 200 when the orchestrator is reconciling. Returns 503 if the store is unreachable or shutting down.
Failure scenarios
Section titled “Failure scenarios”| Scenario | Recovery |
|---|---|
runed crashes | Systemd restarts it. State persists on disk. |
| Disk fills | Reconciler logs errors; new writes fail. Free disk. |
| Docker daemon down | Container ops fail. Process services keep running. |
| KEK file deleted/corrupt | Server refuses to start. Restore from backup. |
| Bootstrap token lost | Recover via local-only rune admin bootstrap (only works on a server with no live tokens — otherwise: restore from backup). |