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.
Minimal example
Section titled “Minimal example”service: name: echo image: busybox scale: 1 command: "/bin/sh" args: ["-c", "echo hello && sleep 60"]Full example
Section titled “Full example”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-balancedField reference
Section titled “Field reference”Top level
Section titled “Top level”| Field | Type | Required | Notes |
|---|---|---|---|
name | string | yes | DNS-1123. Unique within the namespace. |
namespace | string | no | Default default. |
image | string | conditional | Required for container services. |
process | object | conditional | Required for process services. See below. |
scale | int | yes | Desired replicas. 0 to stop. |
labels | map | no | Free-form key/value labels. |
command | string | no | Override 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 | []string | no | Override 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 | []object | no | See below. |
env | map | no | Plain environment variables. |
envFrom | []object | no | Pull env from a secret/config. |
resources | object | no | CPU and memory requests/limits. |
health | object | no | Liveness probes. |
dependencies | []object | no | Service dependencies. |
secretMounts | []object | no | File-mount secrets. |
configMounts | []object | no | File-mount configmaps. |
volumes | []object | no | Persistent volume mounts. See Storage resources. |
expose | object | no | Single-node host exposure. |
discovery | object | no | Internal service discovery. |
affinity | object | no | Placement hints (multi-node, roadmap). |
autoscale | object | no | Autoscaling (roadmap). |
networkPolicy | object | no | Ingress/egress rules. |
securityContext | object | no | Container security (seccomp, capabilities, privileged). See securityContext. |
initSteps | []object | no | One-shot setup containers run before the main container. See initSteps[]. |
skip | bool | no | Skip applying this doc (useful in batch). |
process
Section titled “process”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]| Field | Type | Notes |
|---|---|---|
command | string | Required. Absolute path on host. |
args | []string | Optional. |
workdir | string | Working dir. Defaults to /. |
securityContext | object | See Process runner. |
ports[]
Section titled “ports[]”ports: - name: http port: 8080 protocol: tcp # tcp (default) or udpresources
Section titled “resources”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
Section titled “health.liveness”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: 1See Health checks.
dependencies[]
Section titled “dependencies[]”dependencies: - service: postgres namespace: default readyWhen: healthy # running | healthy | started timeoutSeconds: 60 optional: falsesecretMounts[] / configMounts[]
Section titled “secretMounts[] / configMounts[]”secretMounts: - name: db-secret secretName: db-credentials mountPath: /etc/secrets/db
configMounts: - name: app-config configName: app-settings mountPath: /etc/configEach key in the secret/config becomes a file at <mountPath>/<key>.
envFrom[]
Section titled “envFrom[]”envFrom: - secretRef: db-credentials - configRef: app-settingsEach key becomes an env var. Keys conflicting with explicit env: lose.
volumes[]
Section titled “volumes[]”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| Field | Notes |
|---|---|
name | Mount identifier; unique within the service. |
mountPath | Absolute path. Blocklist: /, /etc, /proc, /sys, /var/run/docker.sock. |
readOnly | Optional. Default false. |
subPath | Optional. Mount a sub-directory of the volume. |
claim | name of an existing Volume. Cross-namespace via FQDN name.ns.rune. |
claimTemplate | storageClassName (optional, falls back to default class), size, accessMode. |
Full schema in Storage resources and the storage concept.
expose
Section titled “expose”expose: port: http # references ports[].name host: api.example.com # optional virtual hostSingle-node only today. Multi-node ingress is roadmap (RUNE-063).
discovery
Section titled “discovery”discovery: mode: load-balanced # round-robin | load-balanced | noneAffects how dependent services resolve this service.
networkPolicy
Section titled “networkPolicy”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).
affinity / autoscale
Section titled “affinity / autoscale”Schemas exist; runtime support is roadmap. Don’t rely on them in single-node deployments today.
securityContext
Section titled “securityContext”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| Field | Type | Notes |
|---|---|---|
seccompProfile.type | string | Unconfined, RuntimeDefault, or Localhost (Kubernetes names). Lowercase aliases (unconfined/default/localhost) also accepted; matching is case-insensitive since v0.0.1-dev.42. |
seccompProfile.localhostProfile | string | Absolute host path. Required iff type: Localhost. |
capAdd | []string | Linux capability names. |
capDrop | []string | Linux capability names; applied after capAdd. |
privileged | bool | Full access to host devices/namespaces. |
Admin-gated.
privileged: trueandseccompProfile.type: unconfinedrequire theservices.privilegedpolicy verb. The built-inreadwritepolicy does not grant it;rootdoes. See Identity & RBAC.
For the process runtime, the process.securityContext block on the
parent governs UID/GID/capabilities differently — see
Process runner.
initSteps[]
Section titled “initSteps[]”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 }| Field | Type | Notes |
|---|---|---|
name | string | Required. DNS-1123 label, unique within the service. |
image | string | Container image. Required for container runtime; must be empty for process runtime. |
command | string | Required. Replaces the image’s ENTRYPOINT. |
args | []string | Replaces the image’s CMD. |
env | map | Merged on top of the parent env; step keys win. |
envFrom | []object | Merged with the parent’s envFrom. |
volumes | []string | Filter over parent volumes. nil = inherit all; [] = none; [a,b] = only those. |
secretMounts | []string | Same convention as volumes. |
configmapMounts | []string | Same convention as volumes. |
resources | object | Step-level override. Inherits parent block when omitted. |
runIf | object | When to run. See Init steps §2. |
timeout | duration | Per-attempt ceiling. 0 defers to the cast-level timeout. |
restartPolicy | string | OnFailure (default) or Never. |
securityContext | object | See securityContext. Inherits parent when omitted; overrides wholesale when set. |
initSteps[].runIf
Section titled “initSteps[].runIf”| Field | Type | Notes |
|---|---|---|
type | string | freshVolume (default), fileMissing, or always. |
path | string | Absolute path inside a parent volume. Required iff type: fileMissing. |
volume | string | Optional parent volume name to restrict the fileMissing check to. |
Validation
Section titled “Validation”Run rune lint before applying — it catches schema errors, undefined references, and dependency cycles.
rune lint api.yaml