Skip to content

Service spec

A service spec is a YAML document with a top-level service: key. Multiple services (and secrets, configmaps, namespaces) can share a single file via --- separators or by repeating the top-level keys.

service:
name: echo
image: busybox
scale: 1
command: "/bin/sh"
args: ["-c", "echo hello && sleep 60"]
service:
name: api
namespace: default
image: ghcr.io/example/api:1.4.0
scale: 3
labels:
app: api
tier: backend
ports:
- name: http
port: 8080
protocol: tcp
env:
LOG_LEVEL: info
NODE_ENV: production
envFrom:
- secretRef: db-credentials
- configRef: app-settings
resources:
cpu:
request: 100m
limit: 500m
memory:
request: 128Mi
limit: 512Mi
health:
liveness:
type: http
path: /healthz
port: 8080
initialDelaySeconds: 5
intervalSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
dependencies:
- service: postgres
readyWhen: healthy
- service: redis
readyWhen: running
secretMounts:
- name: db-secret
secretName: db-credentials
mountPath: /etc/secrets/db
configMounts:
- name: app-config
configName: app-settings
mountPath: /etc/config
expose:
port: http
host: api.example.com
discovery:
mode: load-balanced
FieldTypeRequiredNotes
namestringyesDNS-1123. Unique within the namespace.
namespacestringnoDefault default.
imagestringconditionalRequired for container services.
processobjectconditionalRequired for process services. See below.
scaleintyesDesired replicas. 0 to stop.
labelsmapnoFree-form key/value labels.
commandstringnoOverride the image’s ENTRYPOINT (Kubernetes semantics — command → Entrypoint). Omit to keep the image’s baked-in ENTRYPOINT. Pre-v0.0.1-dev.43 this was silently ignored for the main container; init steps were always honoured (since v0.0.1-dev.38).
args[]stringnoOverride the image’s CMD (args → Cmd). Args without command keeps the image’s ENTRYPOINT and just supplies positional arguments. Pre-v0.0.1-dev.43 also silently ignored for the main container.
ports[]objectnoSee below.
envmapnoPlain environment variables.
envFrom[]objectnoPull env from a secret/config.
resourcesobjectnoCPU and memory requests/limits.
healthobjectnoLiveness probes.
dependencies[]objectnoService dependencies.
secretMounts[]objectnoFile-mount secrets.
configMounts[]objectnoFile-mount configmaps.
volumes[]objectnoPersistent volume mounts. See Storage resources.
exposeobjectnoSingle-node host exposure.
discoveryobjectnoInternal service discovery.
affinityobjectnoPlacement hints (multi-node, roadmap).
autoscaleobjectnoAutoscaling (roadmap).
networkPolicyobjectnoIngress/egress rules.
securityContextobjectnoContainer security (seccomp, capabilities, privileged). See securityContext.
initSteps[]objectnoOne-shot setup containers run before the main container. See initSteps[].
skipboolnoSkip applying this doc (useful in batch).
process:
command: /usr/local/bin/agent
args: ["--config", "/etc/agent.toml"]
workdir: /var/lib/agent
securityContext:
user: rune-agent
group: rune-agent
readOnlyFS: true
capabilities: [NET_BIND_SERVICE]
FieldTypeNotes
commandstringRequired. Absolute path on host.
args[]stringOptional.
workdirstringWorking dir. Defaults to /.
securityContextobjectSee Process runner.
ports:
- name: http
port: 8080
protocol: tcp # tcp (default) or udp
resources:
cpu: { request: 100m, limit: 500m }
memory: { request: 128Mi, limit: 512Mi }

CPU is in milli-cores (100m = 0.1 core). Memory in Ki/Mi/Gi.

health:
liveness:
type: http # or tcp
path: /healthz # http only
port: 8080
scheme: http # http (default) or https; http only
headers: # http only
X-Health-Check: rune
initialDelaySeconds: 5
intervalSeconds: 10
timeoutSeconds: 2
failureThreshold: 3
successThreshold: 1

See Health checks.

dependencies:
- service: postgres
namespace: default
readyWhen: healthy # running | healthy | started
timeoutSeconds: 60
optional: false
secretMounts:
- name: db-secret
secretName: db-credentials
mountPath: /etc/secrets/db
configMounts:
- name: app-config
configName: app-settings
mountPath: /etc/config

Each key in the secret/config becomes a file at <mountPath>/<key>.

envFrom:
- secretRef: db-credentials
- configRef: app-settings

Each key becomes an env var. Keys conflicting with explicit env: lose.

Mount persistent storage. Each entry references either an existing Volume (claim) or asks Rune to auto-provision one per replica (claimTemplate).

volumes:
- name: pgdata
mountPath: /var/lib/postgresql/data
claimTemplate:
storageClassName: local
size: 10Gi
accessMode: ReadWriteOnce
- name: shared
mountPath: /var/lib/shared
readOnly: true
claim:
name: shared-cache
FieldNotes
nameMount identifier; unique within the service.
mountPathAbsolute path. Blocklist: /, /etc, /proc, /sys, /var/run/docker.sock.
readOnlyOptional. Default false.
subPathOptional. Mount a sub-directory of the volume.
claimname of an existing Volume. Cross-namespace via FQDN name.ns.rune.
claimTemplatestorageClassName (optional, falls back to default class), size, accessMode.

Full schema in Storage resources and the storage concept.

expose:
port: http # references ports[].name
host: api.example.com # optional virtual host

Single-node only today. Multi-node ingress is roadmap (RUNE-063).

discovery:
mode: load-balanced # round-robin | load-balanced | none

Affects how dependent services resolve this service.

networkPolicy:
ingress:
- from:
- namespace: default
service: api
ports: [http]
egress:
- to:
- cidr: 0.0.0.0/0
ports: [http]

Schema accepted; runtime enforcement is roadmap (RUNE-080).

Schemas exist; runtime support is roadmap. Don’t rely on them in single-node deployments today.

Container-level security knobs. Applies to the main container when set at service level; init steps inherit the service-level block by default and may override it (see initSteps[]).

securityContext:
seccompProfile:
type: Unconfined # Unconfined | RuntimeDefault | Localhost (case-insensitive)
# localhostProfile: /etc/docker/seccomp/my.json # required iff type=Localhost
capAdd: [SYS_NICE]
capDrop: [ALL]
privileged: false
FieldTypeNotes
seccompProfile.typestringUnconfined, RuntimeDefault, or Localhost (Kubernetes names). Lowercase aliases (unconfined/default/localhost) also accepted; matching is case-insensitive since v0.0.1-dev.42.
seccompProfile.localhostProfilestringAbsolute host path. Required iff type: Localhost.
capAdd[]stringLinux capability names.
capDrop[]stringLinux capability names; applied after capAdd.
privilegedboolFull access to host devices/namespaces.

Admin-gated. privileged: true and seccompProfile.type: unconfined require the services.privileged policy verb. The built-in readwrite policy does not grant it; root does. See Identity & RBAC.

For the process runtime, the process.securityContext block on the parent governs UID/GID/capabilities differently — see Process runner.

One-shot containers (or process subprocesses) that run before the main container on each instance start. See Init steps for the user-facing walk-through.

initSteps:
- name: format
image: ghcr.io/tigerbeetle/tigerbeetle:0.16.30
command: /tigerbeetle
args: ["format", "--cluster=0", "/data/0_0.tigerbeetle"]
runIf:
type: fileMissing
path: /data/0_0.tigerbeetle
timeout: 2m
restartPolicy: OnFailure
securityContext:
seccompProfile: { type: Unconfined }
FieldTypeNotes
namestringRequired. DNS-1123 label, unique within the service.
imagestringContainer image. Required for container runtime; must be empty for process runtime.
commandstringRequired. Replaces the image’s ENTRYPOINT.
args[]stringReplaces the image’s CMD.
envmapMerged on top of the parent env; step keys win.
envFrom[]objectMerged with the parent’s envFrom.
volumes[]stringFilter over parent volumes. nil = inherit all; [] = none; [a,b] = only those.
secretMounts[]stringSame convention as volumes.
configmapMounts[]stringSame convention as volumes.
resourcesobjectStep-level override. Inherits parent block when omitted.
runIfobjectWhen to run. See Init steps §2.
timeoutdurationPer-attempt ceiling. 0 defers to the cast-level timeout.
restartPolicystringOnFailure (default) or Never.
securityContextobjectSee securityContext. Inherits parent when omitted; overrides wholesale when set.
FieldTypeNotes
typestringfreshVolume (default), fileMissing, or always.
pathstringAbsolute path inside a parent volume. Required iff type: fileMissing.
volumestringOptional parent volume name to restrict the fileMissing check to.

Run rune lint before applying — it catches schema errors, undefined references, and dependency cycles.

Terminal window
rune lint api.yaml