Skip to content

BuildKit Kubernetes Driver

FractalOps pins moby/buildkit:v0.31.1 by its amd64 child digest and Buildx v0.35.0 (released 2026-06-17) for the native Kubernetes driver. The direct child pin matches the hard amd64 node placement and the kubelet-reported image ID. Investigation date: 2026-07-14.

  • Assembly GitOps owns the static fractalops-buildx0 Deployment and fractalops-buildx-daemon-config ConfigMap in fractalops-build. CI consumers use builder fractalops-buildx with cleanup: false; Buildx v0.35.0 attaches after its bootstrap GET finds that Deployment and does not mutate the live state.
  • OCI jobs require the buildplane runner label. The dedicated repository runner has exactly one replica and uses RollingUpdate with maxSurge: 0 and maxUnavailable: 1. The old runner stops before its replacement starts, so at most one runner exists and GitHub queues jobs during the zero-available window. The CLI-only build runner retains scheduler-selected placement and has no control-plane or etcd tolerations. It therefore does not compete with the BuildKit cache for a storage worker’s reserved memory. Its complete label set is self-hosted,build,buildplane; omitting broad linux, internal, and k8s labels prevents unrelated workflows from matching this restricted service account. The runner carries only the Docker/Buildx CLI: dockerd is disabled, the pod is not privileged, and all image builds execute on the shared Kubernetes BuildKit Deployment. The manifest renders securityContext.privileged: false explicitly so adoption clears the old live runner’s privileged setting. Its CLI-only container requests 100m CPU, 512Mi memory, and 4Gi ephemeral storage, with limits of 1 CPU, 2Gi memory, and 16Gi ephemeral storage.
  • The live Assembly-owned fractalops-buildx-contract ConfigMap is desired-state authority. Its canonical JSON and SHA-256 cover the exact image, driver options, daemon TOML, and Harbor CA source; consumers read it instead of copying values. Setup passes only attach-driver-opts (namespace, timeout, loadbalance); mutation options remain audit-only because Assembly already owns the workload.
  • BuildKit selects the portable kubernetes.io/os=linux capability instead of a hostname. The scheduler may replace it on another Linux worker after node loss. The runner talks to that shared Deployment over the Kubernetes API and needs no node locality. BuildKit tolerates the bounded sandbox=true worker pool when ordinary workers lack capacity; neither workload tolerates control-plane or etcd taints.
  • The shared pod requests 8Gi and is limited to 30Gi node-local ephemeral storage. An explicit buildkit-root emptyDir mounts /var/lib/buildkit with a 30Gi size limit. GC reserves 6GB, targets at most 24GB, and keeps 12GB free. BuildKit requests 1 CPU and 2Gi memory, is limited to 2 CPU and 3Gi memory, and runs daemon max-parallelism = 1. Scheduler reservation and serialized solves prevent a small worker from entering memory and I/O thrash. This cache survives jobs while the pod survives, but is not recovery data.
  • Steady state is one BuildKit pod and one build runner. BuildKit uses Recreate with rollingUpdate: null; the runner retains the API-compatible RollingUpdate shape but sets surge to zero and unavailable to one. Neither rollout can admit overlapping workers.
  • fractalops-buildx-contract publishes canonical desired JSON and SHA-256 plus explicit image, resources, node selector, driver options, daemon-config hash, and Harbor CA source. The same canonical hash annotates the Deployment pod template, so an Assembly change performs a GitOps-owned Recreate rollout.
  • Stakater Reloader watches fractalops-buildx-daemon-config,daytona-harbor-ca; daemon-config updates and trust-manager CA rotation therefore restart BuildKit without granting the runner write authority.
  • Durable layers use a GHCR registry cache with mode=max. Nexus docker-group mirrors only Docker Hub base-image pulls.
  • trust-manager projects the Harbor CA into ConfigMap fractalops-build/daytona-harbor-ca. GitOps mounts its ca.crt at /tmp/fractalops-buildkit-daytona-harbor-ca.crt; the daemon config trusts that file only for harbor.daytona.svc.cluster.local.
  • runtime-self is the sole owner of Namespace fractalops-build and creates it at wave -20, before trust-manager at wave -10. It preserves argocd.argoproj.io/sync-options: Prune=false from the staged handoff. The child BuildKit chart neither renders the Namespace nor uses CreateNamespace=true, so clean-cluster trust projection has a labeled target without competing owners.
  • Do not set persistent-volume-claim.requests.storage. The native driver then creates a StatefulSet and one PVC per replica; the namespace quota forbids it.
  • Keep docker.io and ghcr.io origins on HTTPS. http = true applies only to the in-cluster Nexus mirror endpoint.
  • Fail before use when the projected Harbor CA is missing or the mounted bytes differ from that ConfigMap; never disable Harbor TLS verification or embed the CA bytes in source. CA content is intentionally not pinned, so cert-manager can rotate it and Reloader can restart BuildKit.
  • Rootful BuildKit requires the namespace’s explicit privileged Pod Security exception. The exception is isolated to this bounded build plane.
  • cleanup: true, another builder name, or different driver options can delete or compete with the shared Deployment. Consumer repositories must contract-test their workflow against this pin.
  • Do not route OCI jobs to general/build labels without buildplane, increase the dedicated runner replica count, or mutate builder state outside Assembly GitOps.
  • The dedicated runner service account may only read the named contract and Deployment, list/read BuildKit pods, and exec into the selected pod. It cannot create, patch, or delete Deployments, ConfigMaps, or pods; Argo remains the only runtime-state writer.
  • Runtime/canary publication may read only daytona-workspace-publisher and agentsquad-canary-harbor-robot. The Harbor TLS private-key Secret is never granted to the build runner.
  • OCI signing uses dedicated roles: read only ClusterSecretStore fractalops-openbao, and create only a token for ServiceAccount external-secrets. The broader general-runner OpenBao bindings remain unchanged and do not include the build service account.
  • Cache export uses ignore-error=true: cache failure degrades to a miss, while image publication still fails closed.

Update the image digest, generated values, contract test, and this page in one commit. Then verify the chart without building an image on the host:

Terminal window
CUE_BIN=.tools/cue/cue platform/k8s/cue-generate.sh lxc-pve-lab
helm template fractalops-build platform/k8s/apps/fractalops-build \
-f platform/k8s/environments/lxc-pve-lab/values/fractalops-build.yaml
pnpm test:build-plane

Authoritative references: Kubernetes driver, Buildx v0.35.0 release, existing-Deployment bootstrap, generated manifest contract, BuildKit configuration, cache garbage collection, and registry cache.