Deployment¶
Reference for the supported deployment shapes. For a guided zero-to-running
walkthrough on Docker Compose with PostgreSQL, see
tutorial_postgres_deployment.md. For
copy-paste quick shapes (local poke, operator pull-and-run, one-shot CLI
in the image), see run_recipes.md. For every
environment variable referenced below, see
environment.md.
The service supports three shapes:
- Container — a single
kneo-servimage with a database you supply. - Compose — the bundled stack that starts the API plus PostgreSQL.
- Embedded —
kneo_serv.service.app:create_app()mounted in your own ASGI server (covered intutorial_custom_tool.md § 7).
Container¶
Pull the published image from GitHub Container Registry:
Tag conventions: <version> (e.g. 1.0.0), <major>.<minor> (1.0),
and latest. amd64-only; arm64 is deferred to
2.0. From 0.3.0 onward the image
is keyless-signed via cosign and ships with a CycloneDX SBOM
attestation; from 0.4.0 onward the release pipeline also runs a
blocking Trivy CVE scan against the pushed digest under the CVSS≥7
policy (security_hardening.md § Image vulnerability scanning)
— verification commands in
supply_chain_review.md § Verification commands.
The image installs the kneo-serv[deploy] extra (psycopg + SDK
telemetry).
Run it against PostgreSQL:
docker run --rm -p 8000:8000 \
-e KNEO_SERV_DATABASE_URL=postgresql://kneo_serv:change-me@host.docker.internal:5432/kneo_serv \
-e KNEO_SERV_AUTH_ENABLED=true \
-e KNEO_SERV_API_KEYS='operator:replace-token:operator' \
ghcr.io/kneo-agent/kneo-serv:latest
For local builds from a source checkout (contributor / pre-publish):
Compose¶
The bundled Compose stack starts the API plus PostgreSQL:
cp deploy/production.env.example deploy/production.env
docker compose --env-file deploy/production.env up --build
Replace every placeholder token and database password before binding the
service to a network. The stack defaults to port 8000; set
KNEO_SERV_PORT to change the host-side port.
For a staging rehearsal, use the staging env example:
cp deploy/staging.env.example deploy/staging.env
KNEO_SERV_ENV_FILE=./deploy/staging.env \
docker compose --env-file deploy/staging.env up --build
deploy/staging.env is gitignored. Keep SDK telemetry argument/result
capture (KNEO_SERV_OTEL_RECORD_ARGUMENTS, KNEO_SERV_OTEL_RECORD_RESULTS)
disabled in staging unless the deployment's data classification has
explicitly approved payload capture.
TLS and reverse proxy¶
The service speaks bare HTTP and does not terminate TLS itself. For any
deployment exposed beyond 127.0.0.1, place a reverse proxy
(nginx, Caddy, AWS ALB, or similar) in front and terminate TLS there.
See tls_and_proxy.md for topology, bind-address
guidance, and trusted-proxy header handling.
Choosing a persistence backend¶
| Backend | When to use |
|---|---|
| SQLite | Local dev or single-process service. Default when KNEO_SERV_DATABASE_URL is unset. |
| PostgreSQL | Any multi-process or production deployment. Set KNEO_SERV_DATABASE_URL. Requires kneo-serv[postgres] or kneo-serv[deploy]. |
When KNEO_SERV_DATABASE_URL is set, the service uses PostgreSQL for run
state, checkpoints, idempotency records, queue leases, locks, audit events,
and workflow continuations. Without it, the service falls back to SQLite for
state and file-backed continuations.
Multi-process SQLite is not a supported topology; see troubleshooting.md § 2.3.
For the throughput and latency trade-offs between the two backends — including why SQLite write throughput does not scale with concurrency — and a bench harness to size your own deployment, see performance.md.
Readiness and liveness¶
Wire these endpoints into your supervisor or load balancer:
GET /livez # process liveness
GET /readyz # readiness: all dependencies healthy
GET /healthz # lightweight overall health
/livez and /readyz are intentionally unauthenticated for probe
integration. /readyz returns 503 with a structured not_ready payload
when any dependency check fails — see
troubleshooting.md § 1.2 for the
failure shape.
The Prometheus scrape endpoint GET /metrics (since 0.5.0) is also
unauthenticated — restrict it to your monitoring network or disable it with
KNEO_SERV_METRICS_ENABLED=false. See
observability.md § Prometheus /metrics.
Workers, scaling, and graceful shutdown¶
A single process runs a pool of KNEO_SERV_WORKER_CONCURRENCY worker threads
(default 1) draining the run queue. Raise it for provider-bound workloads;
for write-concurrent scale on PostgreSQL, run multiple service processes —
each leases queued runs safely via FOR UPDATE SKIP LOCKED. A starting
CPU/RAM/worker floor to deploy against (and the SQLite single-writer caveat) is in
performance.md § Minimum sizing.
On SIGTERM (e.g. a rolling deploy) the service drains the worker pool: workers
stop claiming new work and finish the run they are currently executing, and the
service waits up to KNEO_SERV_SHUTDOWN_TIMEOUT_SECONDS (default 30) for them
to exit. A run still executing when that timeout elapses is interrupted by
process exit — but it stays claimed and is automatically re-leased and retried
by another worker once its KNEO_SERV_WORKER_LEASE_SECONDS lease expires, so it
is not lost, only restarted. To drain in-flight runs without that restart, set
KNEO_SERV_SHUTDOWN_TIMEOUT_SECONDS (and your orchestrator's termination grace
period) at least as long as your longest expected run step. Set
KNEO_SERV_MAX_QUEUE_DEPTH to shed load with 503 under overload, and
KNEO_SERV_QUEUE_MAX_ATTEMPTS (default 5) to dead-letter poison runs rather
than retry them forever.