chore(oci-build): replace bunyip-api stub-cache hacks with cargo-chef (BUNYIP-389) #383
Loading…
Reference in a new issue
No description provided.
Delete branch "chore/BUNYIP-389-cargo-chef-build"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The bunyip-api image build cached dependencies with a hand-rolled stub build: stub sources,
rmglobs that delete the stub artifacts (one of which,.fingerprint/bunyip-*, misses the underscore lib crates), afind -exec touchmtime hack to force the real rebuild, and a belt-and-suspenders 5 MB "stub build leaked" guard. The guard existed only because the process is non-deterministic (v0.2.0 shipped a 557 KB stub, BUNYIP-58), and even on a passing run the real-sources build redundantly recompiled roughly forty dependency crates the cache layer had already built. Fragile and messy: a random-failure surface baked into every build.Change
Replace it with cargo-chef, the standard deterministic Rust-in-Docker dependency cache:
chefbase: rust-builder-musl pluscargo install cargo-chef --locked.planner:cargo chef prepareintorecipe.json.builder:cargo chef cook --release --bin bunyip-api --bin bunyip-e2e-bootstrap(dependencies only, scoped to the api binaries, cached unless the recipe changes), thenCOPY . .andcargo build.No stub sources, no
rmglobs, nofind -exec touch, and no size guard: cargo-chef stubs the workspace internally and deterministically, so no stub can leak and the guard is unnecessary. The export and runtime stages are unchanged; bunyip-web's Dockerfile was already a clean single build and is untouched. The dunite secret / git-config step is preserved for authed mirrors.Verified
docker build --target builderbuilds a realbunyip-api(64 MB) andbunyip-e2e-bootstrap(8.7 MB); the final build compiles only the four workspace crates with no dependency recompile. The cook layer is cached unless the dependency graph changes, so a source-only rebuild is just the roughly four-minute final build.Follow-up (separate)
check.yml's docker step passes no build cache (no
--cache-from/--cache-to), unlike build-api.yml. Adding a buildkit cache there would let the cook layer persist across runs so most check runs hit the fast path instead of a cold cook.The bunyip-api image build cached dependencies with a hand-rolled stub build: it stubbed every crate's source, built the stub, deleted the stub artifacts with globs (one of which, .fingerprint/bunyip-*, missed the underscore lib crates), force-rebuilt the real binary by touching every .rs, and finally a belt-and-suspenders RUN guard failed the build if bunyip-api came out under 5 MB ("stub build leaked"). The guard existed only because the mtime/cache dance was non-deterministic (v0.2.0 shipped a 557 KB stub, BUNYIP-58), and even on a passing run the real-sources build redundantly recompiled roughly forty dependency crates the cache layer had already built. The process was messy and fragile. Replace it with cargo-chef, the standard deterministic Rust-in-Docker dependency cache: a chef base (rust-builder-musl plus cargo install cargo-chef --locked), a planner stage (cargo chef prepare into recipe.json), and a builder stage that cooks the dependency set then builds the workspace. cook is scoped to the two api binaries (cargo chef cook --release --bin bunyip-api --bin bunyip-e2e-bootstrap) so it builds the final build's dependency set rather than the whole workspace, skipping bunyip-web's deps and the resolver-2 feature-variant duplicates the api image does not need. The dunite secret / git-config step is preserved for authed mirrors. Timing (local, at the CARGO_BUILD_JOBS=2 default; CI passes the real nproc/2): the cook layer is cached unless the dependency graph changes, so a source-only rebuild is just the final build (about 4 minutes, only the four workspace crates, no dependency recompile), versus the old approach which redundantly recompiled dependencies on every build. A full cold cook is the tradeoff for determinism. No stub sources, no rm globs, no find -exec touch, and no size guard: cargo-chef stubs the workspace internally and deterministically, so no stub can leak and the guard is unnecessary. The export and runtime stages are unchanged (binary stays at /build/target/release/bunyip-api). bunyip-web's Dockerfile was already a clean single build and is untouched. Verified: docker build --target builder produces a real bunyip-api (64 MB) and bunyip-e2e-bootstrap (8.7 MB), and the final build compiles only the four workspace crates with no dependency recompile. #BUNYIP-389 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>