Control plane
The control plane is the always-on half of a deployment: the backend, which owns the run queue and the published record, and the auth service, which owns the accounts.
Backend
Section titled “Backend”With its default SQLite store the backend owns a database file, an on-disk
definition store, a checkout it ingests from, the run queue, and a headless
browser for rendering references. As a StatefulSet
(deployments/k8s/base/backend.yaml) three things follow from that:
- A single replica. SQLite is single-writer and the store is local, so the
StatefulSetis pinned toreplicas: 1. The backend coordinates publishes, owns the queue, and serves a low-traffic API. - A
PersistentVolumeClaim. Mount it at the SQLite database path inTCAB_BACKEND_DATABASE_URLand at the pathsTCAB_BACKEND_STOREandTCAB_BACKEND_CHECKOUTpoint to, so the database, store, and checkout survive a restart or reschedule. A volume is not a backup; see Backups. - An image with a browser. The published
tcab-backendimage (deployments/images/services.Dockerfile,--target backend) layers the binary over Node, the bundled Playwright driver, and a Playwright-managed Chromium with the fonts it needs, and points the render path at them. SetTCAB_REFERENCE_BROWSERonly to override that baked Chromium with an explicit binary. Thetcab-driverimage carries the same Node and Playwright toolchain plusgit, because the driver seeds, builds, and load-checks each run’s implementation. The auth, dispatcher, and artifact images ship no browser.
The backend image also bakes gg’s reference documents at /opt/gg-reference and
sets TCAB_GG_REFERENCE to point at them. Those are the files the backend serves
at GET /gg/reference, projected by the same gg binary the tcab-driver image
ships and the run images are self-checked against. A backend deployed from the
release tarballs instead needs gg’s v<version>/gg-reference.tar.gz unpacked and
the variable pointed at it; otherwise the console’s gg Reference section answers
503 and the rest of the backend works normally.
The backend Service is ClusterIP with no Ingress. The dispatcher, the
artifact service, the arena, and operators reach it in-cluster, and its outbound
R2 and deploy-hook calls need no inbound exposure.
Wiring variables
Section titled “Wiring variables”Beyond the store and checkout paths, five values wire the backend into the rest of the deployment.
| Variable | Purpose |
|---|---|
TCAB_BACKEND_AUTH_URL | The auth service the backend verifies every bearer token against, in-cluster (http://tcab-auth:8789) |
TCAB_BACKEND_SERVICE_TOKEN | The shared service token the dispatcher’s claim is verified against. It must equal the dispatcher’s copy, or the queue never drains |
TCAB_ARTIFACTS_PUBLIC_URL | The console-facing artifact base URL, reported through GET /config |
TCAB_ARTIFACTS_URL | The in-cluster artifact base URL (http://tcab-artifacts:8790) the backend prunes and sweeps run trees through |
TCAB_ARENA_PUBLIC_URL | The console-facing arena base URL, reported through GET /config |
TCAB_SNAPSHOT_PUBLIC_URL is the public read base of the snapshot bucket,
reported through the same GET /config so the console can load an
asset-generation case’s published
reference frames.
It carries the CDN hostname those objects are served from, which is the value the
static site is built with as TCAB_SNAPSHOT_URL. TCAB_R2_ENDPOINT is a
different thing: the S3 write endpoint the backend uploads the snapshot through.
The snapshot bucket is public-read, which is what lets the public gallery work.
With TCAB_SNAPSHOT_PUBLIC_URL unset the console shows no Reference tab for
asset-generation cases.
Constraints 1 and 2 above are properties of the SQLite store. Point
TCAB_BACKEND_DATABASE_URL at a managed PostgreSQL instance and the backend
becomes a plain Deployment with no database volume and no single-replica pin;
see PostgreSQL. The browser image and a
volume for the definition store and checkout still apply, since those stay on
local disk.
Ingesting definitions
Section titled “Ingesting definitions”The backend serves the catalog from the checkout at TCAB_BACKEND_CHECKOUT,
populated by POST /ingest. There are two shapes for driving that, and an
overlay uses one of them.
- A
CronJob(deployments/k8s/base/ingest-cronjob.yaml) that clones the repository and callsPOST /ingestover the cluster network. It fits a deployment whose backend serves its checkout from a shared volume the job can mount. - An ingest sidecar in the backend pod, which the
stagingandprodoverlays patch in (patch-backend-ingest.yaml). It shares the backend’sstatevolume, writes the checkout the backend reads, and callsPOST /ingestover localhost, so intra-pod traffic bypasses theNetworkPolicyand no service token is needed. It runs one forced ingest of the branch tip on backend start, then idles. Those overlays suspend the baseCronJob.
Every pipeline deploy changes the backend’s image tag, so every deploy restarts
the backend pod, and the sidecar re-ingests the catalog that shipped with the
commit. It ingests once rather than on a schedule: a periodic forced re-ingest
rewrites every version and briefly leaves each one without a manifest, which
fails any run resolving that version mid-cycle. Publish catalog changes between
deploys with scripts/reingest-cluster.sh --env <env>, which fetches the branch
tip into the live checkout and forces one re-ingest. The backend swaps each
version into place atomically, so it is safe to run while runs execute.
Auth service
Section titled “Auth service”The auth service hosts the user
accounts the backend verifies tokens
against. It keeps its own SQLite database, so it takes the same single-replica
StatefulSet plus PersistentVolumeClaim shape as the backend, or runs as a
plain Deployment when TCAB_AUTH_DATABASE_URL points at a managed database.
It renders nothing, holds no third-party secret, and stores only Argon2id
password hashes. The example is deployments/k8s/base/auth.yaml; point the
backend at it with TCAB_BACKEND_AUTH_URL=http://tcab-auth:8789.