Skip to main content

ADR-0003: Builds run as Kubernetes Jobs with rootless BuildKit

Status

Accepted

Context

The operator must never build images in-process: builds are heavy, bursty, and run untrusted user code (npm ci executes arbitrary scripts).

Decision

Each Release gets a Job. The build container is the runtime's toolchain image (from platform config); the static pagifier-builder binary and buildctl are injected via an init container; a rootless buildkitd sidecar builds and pushes the image. No privileged pods, no Docker socket, no kaniko fork risk.

Consequences

  • Untrusted build code runs in the tenant namespace under restricted PSA, bounded by Job deadlines and resource limits.
  • The toolchain image is platform-controlled configuration — supporting a new Node version is an S3 upload, not an operator release.
  • Server config (nginx.conf) is deliberately NOT baked into images: it mounts from a ConfigMap, so declarative header/cache changes redeploy without rebuilding.
  • Cost: one buildkitd per build (no shared cache in V1). A shared BuildKit pool with cache volumes is the planned optimization.