The jekyo.yaml file
Volumes & state
Databases and stateful services keep their data across deploys, restarts, and even jekyo down. Backups run on a schedule and restore with one command.
Declaring volumes
app: shop
services:
db:
image: pgvector/pgvector:pg16
env:
POSTGRES_PASSWORD: ${PG_PASSWORD}
port: 5432
volumes:
pgdata: /var/lib/postgresql/data # name -> mount path
volumes:
pgdata:
size: 10Gi
Two parts: the service mounts a named volume, and the top-level volumes: block declares it. Declaring an unused volume, or mounting an undeclared one, is a validation error.
Volume options
| Key | Type | Default | Description |
|---|---|---|---|
size | string | required | Storage size, for example 10Gi. |
class | string | local-path | Storage class. |
backup | map | Scheduled backups. See Backups. |
Sharing a volume between services
Give the mount a subpath and several services can share one volume (and one size):
services:
app:
volumes:
data:
path: /var/lib/app
subpath: app
db:
volumes:
data:
path: /var/lib/mysql
subpath: mysql
volumes:
data:
size: 10Gi
Lifecycle
| Command | Effect on data |
|---|---|
jekyo up | Never touches volumes. Redeploys reuse them. |
jekyo down shop | Removes workloads. Volumes are kept. |
jekyo down shop --volumes | Deletes volumes too. Asks for confirmation. |
This asymmetry is deliberate: destroying compute is routine, destroying data never is.
Backups
Backups are encrypted snapshots (restic) sent to any S3-compatible storage: AWS S3, Cloudflare R2, Backblaze B2, or a MinIO you host yourself.
1. Set the target, once per cluster
jekyo backup config \
--endpoint https://s3.eu-central-1.amazonaws.com \
--bucket my-backups \
--access-key AKIA... \
--secret-key ...
An encryption password is generated and stored in the cluster. Export a copy somewhere safe: without it, backups cannot be read.
2. Schedule it in jekyo.yaml
volumes:
pgdata:
size: 10Gi
backup:
schedule: "0 3 * * *" # every night at 03:00
keep: 7 # snapshots to retain
jekyo init offers this automatically for every volume a template ships: answer 15m, hourly, daily, weekly, or a cron expression. Non-interactive: jekyo init postgres --defaults --backup daily.
Backup options
| Key | Type | Default | Description |
|---|---|---|---|
schedule | string | required | Cron expression for snapshot timing. |
keep | int | 7 | Snapshots retained; older ones are pruned. |
3. Operate
jekyo backup now shop/pgdata # snapshot immediately
jekyo backup ls shop/pgdata # list snapshots
jekyo backup restore shop/pgdata # restore the latest
jekyo backup restore shop/pgdata a1b2c3 # restore a specific snapshot
Restore is safe by construction: it asks for confirmation, stops the workloads using the volume, replaces the volume contents with the snapshot, and starts the workloads again.
Snapshots are per volume, per app
Each volume gets its own encrypted repository under bucket/<app>/<volume>. Deleting an app with --volumes does not delete its backups; they remain restorable after a redeploy.
Current constraints
- Volumes are node-local (fast, simple). Off-server durability is exactly what backups are for.
replicas > 1together with volumes is rejected. Per-replica volumes are on the roadmap.
Local backups
No S3 account? jekyo backup config --local keeps restic repositories on the server itself at /var/lib/jekyo/backups. Mount a dedicated disk at that path for real durability: a backup on the disk that dies with the data protects against mistakes, not hardware. Everything else (schedules, backup now, ls, restore) works identically.