The jekyo.yaml file

Services

A service is one container: an image you reference or source you build, plus its runtime configuration.


Reference

Every key a service accepts. Each links to detail below or to a dedicated page.

KeyTypeDefaultDescription
imagestringContainer image to run. Exactly one of image or build is required.
buildmapBuild from source instead. See Build options.
commandlistimage entrypointOverride the container entrypoint.
argslistimage cmdArguments passed to the entrypoint.
envmapEnvironment variables. Values support ${VAR} interpolation.
portintMain container port. Shorthand for a one-element ports.
portslist of intAll container ports. The first is the main port.
httpmapPublish on a domain with automatic TLS. See Domains & TLS.
exposelistPublish raw TCP/UDP ports on the node. See Domains & TLS.
resourcesmapunlimitedCPU and memory. See Resources.
replicasint1Number of instances. Not allowed together with volumes.
statefulboolautoForce stateful deployment. Implied by volumes.
healthmapReadiness and liveness probes. See Health checks.
gpuint or mapRun on the NVIDIA runtime. See GPU workloads.
schedulestringCron expression. Turns the service into a scheduled job. See Scheduled jobs.
volumesmapPersistent storage mounts. See Volumes & state.

Image or build

Exactly one of the two:

services:
  api:
    image: ghcr.io/acme/api:1.4      # run a prebuilt image

  worker:
    build:                            # or build from source
      context: .
      dockerfile: Dockerfile
      args:
        VERSION: "1.4"

  tools:
    build:
      context: .
      inline: |                       # or write the Dockerfile inline
        FROM alpine:3.20
        RUN apk add --no-cache curl jq

Build options

KeyTypeDefaultDescription
contextstring.Build context directory, relative to jekyo.yaml.
dockerfilestringDockerfilePath to a Dockerfile. Mutually exclusive with inline.
inlinestringLiteral Dockerfile contents. Mutually exclusive with dockerfile.
argsmapBuild arguments.

Built images are tagged by a content hash of the context, Dockerfile, args, and target platform. Unchanged sources never rebuild. See Building images.

Configuration

    command: ["./server"]
    args: ["--verbose"]
    env:
      MODE: production
      SECRET: ${MY_SECRET}

${VAR} values come from your environment or --env-file .env. An unset variable fails the deploy immediately. Escape a literal dollar sign as $$.

Ports

    port: 8080          # the common case
    ports: [8080, 9090] # several ports

The first port is the main one: the default target for http routing and health probes. Services in the same app reach each other by service name, for example db:5432.

Resources

    resources:
      cpu: 500m         # guaranteed
      memory: 512Mi     # guaranteed
      cpu-max: "2"      # hard cap (optional)
      memory-max: 2Gi   # hard cap (optional)
KeyMeaning
cpu, memoryWhat the service is guaranteed. The scheduler reserves it.
cpu-max, memory-maxHard caps. The service cannot exceed them.

Unset means unset: no implicit limits.

Health checks

One block produces both probes: readiness (no traffic until healthy) and liveness (restart when stuck).

    health:
      path: /healthz    # HTTP probe on the main port
    health:
      command: ["mysqladmin", "ping", "-h", "127.0.0.1"]   # exec probe
KeyTypeDefaultDescription
pathstringHTTP GET path that must return 2xx/3xx.
portintmain portPort for the HTTP probe.
commandlistExec probe. Exit 0 means healthy. Mutually exclusive with path.

Beyond the basics

Everything below came from real apps hitting real walls; each key is optional and composes with the rest.

KeyWhat it does
secrets:Like env:, but delivered via a Kubernetes Secret and secretKeyRef. Never an inline literal, redacted in jekyo render.
files:Mount operator-supplied files. A local path becomes a ConfigMap entry; {from: ${VAR}, mode: "0600"} becomes a Secret. No image rebuild to change config.
init:Run-to-completion containers (schema migrations) before the service starts. Inherit env, secrets, and volumes.
sidecars:Extra containers in the same pod: log shippers, exporters, adapters. Share volumes and localhost.
stop-grace:Seconds to drain on shutdown (terminationGracePeriodSeconds).
shm:Size /dev/shm. Browser workloads want 1Gi.
security:run-as, read-only-root, no-new-privileges; runtime default seccomp.
caps:Extra Linux capabilities, e.g. NET_ADMIN.
network.hostHost networking for workloads that bind node addresses.
network.egressrestricted (public internet only; cluster, RFC1918 and metadata blocked) or internal (cluster only). Enforced NetworkPolicy, with allow: CIDR exceptions.
placement:Node selector: and tolerate: for pinning services to nodes.
metrics:Declares a scrape endpoint; renders Prometheus annotations.
expose.hostPublish raw TCP/UDP on a conventional host port (not just NodePorts).
health.graceStartup budget in seconds; slow starters are not killed while booting.

Health checks wire three probes from one declaration: a startup probe that owns the boot budget, a readiness probe that sheds traffic without killing the pod, and a liveness probe that restarts only a wedged process.

Sidecars in practice

Sidecars are full citizens: they can build from your repo like any service, and caps: and security: apply per container, so one privileged helper does not widen the main process.

services:
  web:
    build: .
    port: 8080
    security:
      run-as: 1000        # the app itself stays unprivileged
    sidecars:
      proxy:
        build: ./proxy    # built and tagged alongside the service
        caps: [NET_ADMIN] # only this container gets the capability

The CLI addresses containers with app/service/container targets, and a sidecar name also resolves as the second segment when no service matches, so the short form works everywhere:

jekyo logs shop/proxy -f          # just the sidecar's logs
jekyo exec shop/proxy -- ip route # a shell or command inside it
jekyo ps shop                     # sidecars listed under their service

The same per-container keys work on init: containers, which covers the setup-then-exit pattern: a privileged init container configures the network or filesystem, exits, and the long-running containers keep no extra privileges at all.

Previous
Overview