How Glidepath built images with kaniko, what rootless BuildKit would change, and a phased plan to switch.
Since then. The switch happened the same day, faster than the five phases planned: ADR-0026 was accepted on October 17, 2026, build-image now runs one rootless BuildKit step for every platform, kaniko and crane are gone, the Go scaffold cross-compiles from $BUILDPLATFORM, and every -cicd namespace enforces Pod Security baseline. This page is the review as written.
v1.24.0-debug is the last Google release, so there are no more CVE fixes. Chainguard's fork publishes no public images.FROM --platform=$BUILDPLATFORM, so every RUN step of the amd64 build runs under QEMU on the arm64 node. That breaks Go (known gap #37) and costs Backstage 11 of its 25 minutes.app-*-cicd build namespaces carry no pod-security enforce label, Tekton runs with set-security-context=false, and kaniko runs as root in the container. ADR-0010 and security.md need correcting whichever builder you keep.Recommendation. Move to rootless BuildKit, daemonless, one instance per TaskRun (no shared daemon, so tenant isolation holds). Roll it out inside the existing build-image Task behind a per-app build.builder flag, canary on four apps, then flip the default and remove kaniko and crane.
build-imageThe two legs run one after the other. The emulated one is where the time goes.
Each kaniko step uses a busybox gate script to skip itself when its arch isn't requested, because Tekton has no per-step when:. Each step also overrides SSL_CERT_FILE, since Tekton injects a CA directory that doesn't exist in the kaniko image. Labels and HANGAR_VERSION/HANGAR_GIT_REVISION build-args are set on both steps. The cache is kaniko's registry layer cache (--cache=true, 336h).
GoogleContainerTools/kaniko was archived in June 2025, and v1.24.0 was the last release. The pin in build-image.yaml carries no CVE fixes from here on. Chainguard's fork is maintained for security only and its images are for Chainguard customers. The osscontainertools fork is community-run.
Evidenceimage: gcr.io/kaniko-project/executor:v1.24.0-debug on both build steps; the step comment already notes no newer tag exists.
With --custom-platform set, kaniko runs every stage as the target arch and ignores a per-stage --platform. Go crashes under QEMU (two separate QEMU bugs, one with no mitigation). Java and Node builds inside a Containerfile run several times slower. The current workaround is to compile in build.sh and keep a thin Containerfile, which the Spring scaffold doesn't do yet.
Evidenceknown-gaps #37 (smoke-ecs, boarding-api); pipeline-performance.md "amd64 builds under QEMU"; flight-api Spring build 17 min with the two steps one after the other.
ADR-0010, rootless-builds.md and security.md say builds run under PSS restricted. Live, only autopilot-runs and autopilot-system enforce restricted. Kaniko also needs root inside its container, so it could never pass restricted. Today the build pods are root containers with no admission control over their security context.
Evidencekubectl get ns on the dev cluster: 31 app-* namespaces without pod-security.kubernetes.io/enforce; feature-flags set-security-context=false; no Kyverno policy covering pod security for builds.
Kaniko only produces single-platform images, so crane assembles the index and the -arm64/-amd64 tags stay published. It works, but it is one more image pinned by digest to a floating :debug tag, plus a gate script per arch.
| Area | Kaniko (today) | Rootless BuildKit |
|---|---|---|
| Maintenance | archived v1.24.0 is the last Google release. Forks are security-only or community-run. | active Maintained by moby/Docker; the engine behind buildx. |
| Cross-arch | all emulated Every stage runs as the target arch. | native compile--platform=$BUILDPLATFORM is honoured, so Go and Java cross-compile without QEMU. Only steps that truly run on the target arch are emulated. |
| Multi-arch output | Two steps one after the other, then crane. | One run builds both platforms in parallel and pushes the index. |
| Cache | Registry layer cache. | Registry cache in mode=max, RUN --mount=type=cache, stages run in parallel. |
| Build features | No RUN --mount=type=secret or ssh. | Full Dockerfile frontend. |
| Privilege | root Passes baseline, fails restricted. | UID 1000, unconfined Needs seccomp and AppArmor Unconfined (or Localhost profiles), so it fails baseline as shipped. hostUsers: false may close the gap; the spike tests it. |
| Tekton fit | proven here Every workaround is documented. | New step image. Re-check the CA path quirk; take the digest from --metadata-file. |
| Supply chain | Chains reads IMAGE_URL and IMAGE_DIGEST. | Same results. buildctl adds no attestation manifests unless asked, so Conforma and verify-image-provenance are unaffected. |
The main con: on paper BuildKit's rootless default is less restricted than kaniko, because seccomp and AppArmor are unconfined. In practice you're trading a non-root user with no syscall filter for root with no filters. If you later enforce baseline on the cicd namespaces, BuildKit needs Localhost profiles or user namespaces.
ADR-0010's documented fallback. It needs the same privilege relaxations, and multi-arch through buildah manifest is clunkier. No reason to prefer it.
Gives a warm local cache, but one daemon builds for every tenant, which breaks the ADR-0011 two-namespace isolation. Rejected.
Removes QEMU for any builder, but there's no amd64 hardware for the dev cluster. It complements the switch; it doesn't replace it.
Derive platforms from the cluster registry arch and move every scaffold to build.sh. That helps, but the builder stays archived and Go multi-arch stays broken.
moby/buildkit:<pin>-rootless and buildctl-daemonless.sh.registry-credentials; TLS under Tekton's injected SSL_CERT_DIR; one-run multi-arch index; digest from --metadata-file.hostUsers: false).rootless-builds.md and security.md now, whatever the outcome.Exit Go/no-go for each item, with the exact working step YAML.
build-and-push-buildkit step to build-image, using the same exit 0 gate as the arch steps.build.builder: kaniko | buildkit in cicd.schema.json, default kaniko. The schema change means a toolbox rebuild.<repo>:buildcache, mode=max, per app and per tenant.Exit A kaniko app and a buildkit app both pass build, sign and provenance checks.
FROM --platform=$BUILDPLATFORM with GOARCH=$TARGETARCH. Bump all three airframe chart pin locations.Exit Every canary is green with a measured improvement on the amd64 path.
buildkit the default. ADR-0026 supersedes ADR-0010 with the real privilege model.rootless-builds.md, security.md, pipeline-performance.md, cicd-yaml-reference.md and the build-image header; close known-gap #37.GlidepathTab.tsx.Exit No app sets builder: kaniko, after a full week of builds.
build.builder.-arm64/-amd64 tags stop being published. Grep the gitops repos for them first.hostUsers: false; containerd 2.3.1 and Kubernetes 1.36 on the dev cluster support user namespaces.kube-system/binfmt DaemonSet.:buildcache needs to be excluded from Tower's image prune and from release tag lists.Sources
Glidepath sources: charts/glidepath-catalog/templates/tasks/build-image.yaml, docs/admin/adr/0010-kaniko-rootless-builds.md, docs/admin/known-gaps.md, docs/admin/pipeline-performance.md. Live state from the dev cluster on October 17, 2026.