Skip to content

build: use nix for building release images#3549

Open
DSharifi wants to merge 9 commits into
mainfrom
dsharifi/nix-builds
Open

build: use nix for building release images#3549
DSharifi wants to merge 9 commits into
mainfrom
dsharifi/nix-builds

Conversation

@DSharifi

Copy link
Copy Markdown
Contributor

No description provided.

DSharifi and others added 9 commits May 7, 2026 15:27
# Conflicts:
#	.github/workflows/docker_build_node.yml
#	.github/workflows/docker_build_node_gcp.yml
#	.github/workflows/docker_build_rust_launcher.yml
#	deployment/build-images.sh
#	docs/reproducible-builds.md
#	flake.nix
#	nix/mpc-node.nix
#	scripts/build-and-verify-rust-launcher-docker-image.sh
The script is kept as the lean entry point for the release workflows per
review feedback on #3171.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
build-images.sh now needs nothing but nix and git: skopeo is re-exported
from the flake (pinned through flake.lock, the same binary image-dir.nix
uses) and invoked with `nix run .#skopeo`. Removes the apt install step
from the three docker build workflows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@DSharifi DSharifi marked this pull request as ready for review June 12, 2026 13:40
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Pull request overview

This PR migrates the reproducible Docker image build pipeline from repro-env/repro-sources-list.sh/Buildkit to Nix. Each image (mpc-node, mpc-node-gcp, rust-launcher) is now a dockerTools.buildLayeredImage derivation; a companion *-image-dir derivation produces the skopeo dir: layout that gets pushed, and a *-manifest-digest derivation hashes that exact layout — so the digest operators vote for is computed deterministically inside the Nix sandbox and is independent of the pushing skopeo. The shared Rust-binary plumbing (vendor dir, crane setup, env knobs, path remaps) is factored from nix/mpc-node.nix into nix/rust-build-common.nix and reused for tee-launcher.

Changes:

  • Delete deployment/Dockerfile-{node,node-gcp,rust-launcher} and repro-sources-list.sh; their role is replaced by Nix derivations under nix/.
  • Add nix/rust-build-common.nix (shared buildRustBin builder), nix/tee-launcher.nix, the three *-image.nix files, nix/image-dir.nix, and nix/image-manifest-digest.nix.
  • Refactor nix/mpc-node.nix to call buildRustBin and inject BUILT_OVERRIDE_mpc_node_GIT_COMMIT_HASH_SHORT (sandbox has no .git).
  • Rewrite deployment/build-images.sh and scripts/build-and-verify-rust-launcher-docker-image.sh as thin wrappers over the flake.
  • Update CI: install Nix + restore-nix-cache action on the CI test job; remove repro-env install steps from all four workflows; bump push runners to warp-ubuntu-2404-x64-32x.
  • Update README.md, docs/reproducible-builds.md, docs/localnet/docker-localnet.md, and the TDX external guide to reflect the Nix-driven flow.

Reviewed changes

Per-file summary
File Description
.github/workflows/ci.yml Replace repro-env install with Install Nix + restore-nix-cache; build image via nix build and docker load
.github/workflows/docker_build_node.yml Same migration; bump runner 16x→32x; no restore-nix-cache step
.github/workflows/docker_build_node_gcp.yml Same migration for the GCP variant
.github/workflows/docker_build_rust_launcher.yml Same migration; runner 8x→32x; no restore-nix-cache step
README.md Mention Nix-based reproducible build flow
deployment/Dockerfile-node* (3 files) Deleted; replaced by nix/*-image.nix derivations
deployment/build-images.sh Rewrite as a thin wrapper that calls nix build .#{mpc-node,*-image-dir,*-manifest-digest} and skopeo via nix run .#skopeo
deployment/repro-sources-list.sh Deleted (no longer used)
docs/localnet/docker-localnet.md Use nix build .#node-image instead of the legacy script invocation
docs/reproducible-builds.md Rewrite around Nix derivations; document nix build .#mpc-node, nix build .#node-image-manifest-digest, push via nix run .#skopeo
docs/running-an-mpc-node-in-tdx-external-guide.md Drop repro-env/docker-buildx/skopeo prereqs in favor of nix
flake.nix Expose mpc-node, tee-launcher, the three *-image outputs (Linux only), *-image-dir, *-manifest-digest, and skopeo; inject gitCommitHashShort from self.shortRev
nix/image-dir.nix New: convert dockerTools archive into skopeo dir: layout inside the sandbox using --insecure-policy + --tmpdir
nix/image-manifest-digest.nix New: hash manifest.json from the dir: layout into sha256:<hex>\n
nix/mpc-node.nix Slim down to crate-specific bits (link deps, BUILT_OVERRIDE_... extraEnv); delegate everything else to buildRustBin
nix/node-image.nix, nix/node-gcp-image.nix, nix/rust-launcher-image.nix New: dockerTools.buildLayeredImage recipes pulling in bash/coreutils/python/cacert (+ gcloud or docker-client as appropriate) and the entry script
nix/rust-build-common.nix New: shared crane-based Rust builder — source filter, vendor-dir near-jsonrpc workaround, repro env, preBuild path remap, accepts crate-specific pname/cargoExtraArgs/buildInputs/extraEnv
nix/tee-launcher.nix New: 13-line leaf — pure-Rust crate, no extra C deps
scripts/build-and-verify-rust-launcher-docker-image.sh Replace skopeo+manual sha256 with nix build .#rust-launcher-image-manifest-digest && cat result-rust-launcher-digest

Findings

Non-blocking (nits, follow-ups, suggestions):

  • .github/workflows/docker_build_node.yml:29, docker_build_node_gcp.yml:29, docker_build_rust_launcher.yml:29 — the three release/push workflows install Nix but never run ./.github/actions/restore-nix-cache. Every push to main / release/v* will therefore cold-build mpc-node and the OCI image from scratch (the CI test jobs do use the cache action). The 16x→32x runner bump softens the wall-clock cost but doesn't eliminate it. If the intent was to skip the cache for release builds (e.g. to guarantee no contamination from a poisoned cache), a one-line comment would prevent future confusion; otherwise consider adding the restore step.
  • deployment/build-images.sh:85nix build --no-link --print-out-paths deliberately skips creating a result symlink, so the store paths returned by nix_out are not GC-rooted between that call and the subsequent sha256sum / skopeo copy that consumes them. In CI this is fine (no GC happens mid-job), but on a developer machine with auto-GC or aggressive min-free it is theoretically possible for the store path to disappear between commands. Adding --out-link for the final-stage outputs (or pinning them as GC roots) would make local runs more robust.
  • flake.nix:79gitCommitHashShort = self.shortRev or self.dirtyShortRev or \"unknown\";. The \"unknown\" branch is reached when the flake is evaluated from a source tree without git metadata (e.g. a tarball, or nix flake against a non-git path). In that case mpc-node --version would silently report unknown rather than a real commit. This matches the documented intent but worth a one-line note that \"unknown\" means no rev was available — the dirty case already has its own branch above.
  • nix/image-dir.nix:38 — the --insecure-policy flag is fine and the justification is sound (local archive→dir copy, no registry signatures involved), but worth being explicit for future readers: this flag is only safe because both source and destination are local formats. If anyone later changes the source to e.g. docker://..., that flag must be removed or it would silently skip signature verification on a network pull.
  • nix/image-manifest-digest.nix:14 — the result file ends in sha256:<hex>\n. Consumers using \$(cat ...) strip the trailing newline; consumers using < \$out would see it. No bug today, but consider printf 'sha256:%s' ... (no trailing newline) or a comment documenting the format.
  • nix/rust-build-common.nix (the cargoArtifacts / buildPackage split) — putting BUILT_OVERRIDE_mpc_node_GIT_COMMIT_HASH_SHORT in extraEnv correctly avoids re-keying the dep cache on each commit, but this only works because cargo treats env-var changes as a rebuild trigger for the root crate's build script (where built runs), not for the cached deps. If built ever migrates to a transitive dep, the override would silently stop affecting the binary. Worth either a comment near extraEnv or, defensively, a CI assertion that mpc-node --version reports the expected short SHA.

✅ Approved — no blocking issues. The Nix-based pipeline is well-factored: shared builder + per-crate leaves, separated image / dir / digest stages so the digest is provably the bytes that get pushed, and the documentation alignment is thorough. The cold-cache cost on release pushes is the most concrete operational follow-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant