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.
| Key | Type | Default | Description |
|---|---|---|---|
image | string | Container image to run. Exactly one of image or build is required. | |
build | map | Build from source instead. See Build options. | |
command | list | image entrypoint | Override the container entrypoint. |
args | list | image cmd | Arguments passed to the entrypoint. |
env | map | Environment variables. Values support ${VAR} interpolation. | |
port | int | Main container port. Shorthand for a one-element ports. | |
ports | list of int | All container ports. The first is the main port. | |
http | map | Publish on a domain with automatic TLS. See Domains & TLS. | |
expose | list | Publish raw TCP/UDP ports on the node. See Domains & TLS. | |
resources | map | unlimited | CPU and memory. See Resources. |
replicas | int | 1 | Number of instances. Not allowed together with volumes. |
stateful | bool | auto | Force stateful deployment. Implied by volumes. |
health | map | Readiness and liveness probes. See Health checks. | |
gpu | int or map | Run on the NVIDIA runtime. See GPU workloads. | |
schedule | string | Cron expression. Turns the service into a scheduled job. See Scheduled jobs. | |
volumes | map | Persistent 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
| Key | Type | Default | Description |
|---|---|---|---|
context | string | . | Build context directory, relative to jekyo.yaml. |
dockerfile | string | Dockerfile | Path to a Dockerfile. Mutually exclusive with inline. |
inline | string | Literal Dockerfile contents. Mutually exclusive with dockerfile. | |
args | map | Build 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)
| Key | Meaning |
|---|---|
cpu, memory | What the service is guaranteed. The scheduler reserves it. |
cpu-max, memory-max | Hard 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
| Key | Type | Default | Description |
|---|---|---|---|
path | string | HTTP GET path that must return 2xx/3xx. | |
port | int | main port | Port for the HTTP probe. |
command | list | Exec 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.
| Key | What 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.host | Host networking for workloads that bind node addresses. |
network.egress | restricted (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.host | Publish raw TCP/UDP on a conventional host port (not just NodePorts). |
health.grace | Startup 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.