Skip to content

kubrain.yaml

kubrain.yaml lives in your repository and travels with every release. It describes what to build and how to run it; the cloud renders Kubernetes objects from it with a deterministic engine, so kubrain deploy validate locally matches what the cloud produces. It comes in two mutually-exclusive shapes.

Flat (single component)

build:
  dockerfile: Dockerfile      # path relative to the context root; OR
  # buildpack: auto           # no Dockerfile → Cloud Native Buildpacks / Nixpacks
port: 8080                    # container port
command: ["./server"]         # optional; overrides the image entrypoint
replicas: 3
resources:
  ram: 512Mi                  # billed dimension
health:
  path: /healthz              # probe path
  # port: 8080                # defaults to the top-level port
env:                          # each entry is ONE of four forms (see Secrets & env)
  LOG_LEVEL: info                                   # 1. literal value
  DB_PASSWORD: {secret: db-app, key: password}      # 2. from a Secret key
  TUNING: {configMap: app-config, key: level}       # 3. from a ConfigMap key
  REDIS_URL: {addon: redis, key: url}               # 4. from a built-in addon's Secret
envFrom:                      # import every key of a Secret/ConfigMap as env vars
  - secret: db-app            #   (add `prefix: FOO_` to namespace the keys)
  - addon: redis
service:
  enabled: true               # default true when `port` is set
  type: ClusterIP             # ClusterIP | LoadBalancer
ingress:
  enabled: true               # default true when any host is set
  host: app.example.com       # shorthand for a single host
  # hosts: [app.example.com, www.app.example.com]  # multiple hosts on one cert
  tls: true                   # one SAN cert covering all hosts, via cert-manager
deployment:
  strategy: RollingUpdate     # RollingUpdate | Recreate

Multi-component

A deployment can be several workloads that ship as one release and roll/rollback together:

components:
  web:
    build: {dockerfile: Dockerfile}
    port: 8080
    replicas: 3
    ingress: {enabled: true, host: app.example.com, tls: true}
    env: {LOG_LEVEL: info}
  worker:
    build: {dockerfile: Dockerfile.worker}
    command: ["./worker"]
    service: {enabled: false}      # a background worker needs no Service
  redis:
    image: redis:7-alpine          # prebuilt dependency — NOT built from source
    port: 6379
    service: {enabled: true}       # reachable as <deployment>-redis:6379

Rules that matter

  • Flat and components: are mutually exclusive.
  • A component has either build: (built from source) or image: (prebuilt) — never both. Prebuilt components skip the build.
  • Each built component’s image is named <deployment>-<component> (e.g. myapp-web); a flat app builds one image named for the deployment.
  • Components find each other by the derived Service name <deployment>-<component> on their port — inject those addresses via env.

Secrets & env

Each env: entry is exactly one of four forms (the validator rejects combinations, e.g. a literal alongside a ref):

FormSyntaxBecomes
1. LiteralNAME: valuevalue: — no lookup
2. Secret keyNAME: {secret: s, key: k}secretKeyRef
3. ConfigMap keyNAME: {configMap: c, key: k}configMapKeyRef
4. Addon credentialNAME: {addon: redis, key: url}a resolved secretKeyRef

key: defaults to the env var’s own name when omitted. envFrom: mirrors forms 2–4 for whole-secret/ConfigMap import (each entry sets exactly one of secret:, configMap:, or addon:, plus an optional prefix:). A namespace: on a Secret ref makes Kubrain mirror that Secret into the app’s namespace at rollout (re-synced each deploy, so rotation follows).

Values set via set_secret are referenced, never baked into the image — so rollback and promotion keep working and pick up current values on the next deploy.

Custom manifests

Kubrain renders from templates, resolved per kind:

  1. Built-in presets — Deployment (always), Service and Ingress (when enabled). Enough for most apps.
  2. Per-repo override — a file at kubrain/k8s-templates/<kind>.yaml (deployment.yaml, service.yaml, ingress.yaml) replaces the built-in for that kind. Use for a StatefulSet, custom annotations, etc.
  3. Extra resources — any other file in kubrain/k8s-templates/ (a cronjob.yaml, hpa.yaml, a CRD) renders as an additional object applied with the release.

Any custom workload template must reference {{ .Image }} (the built digest for the current component). Iterate with kubrain deploy render --dir <dir> to see the exact objects before shipping.

Storage

Every cluster ships a default StorageClass kubrain. Declare a standard PVC (accessModes: ["ReadWriteOnce"], storageClassName: kubrain); it binds when a pod first uses it, and data survives restarts and reschedules. Design around the RWO access mode — single-instance stateful workloads use replicas: 1 + one PVC

  • deployment.strategy: Recreate; multi-replica stateful workloads use a StatefulSet override with volumeClaimTemplates. Volumes bill at €0.05/GiB-month (first 20 GiB free).

See also

  • Quickstart — where kubrain.yaml fits in the ship flow.
  • MCP toolsdeploy, set_secret, validate.