Skip to content

Fast Docker build: cache mounts, layer ordering, multi-stage nvim - #15

Open
IlyaasK wants to merge 2 commits into
PufferAI:4.0from
IlyaasK:fast-docker-build
Open

Fast Docker build: cache mounts, layer ordering, multi-stage nvim#15
IlyaasK wants to merge 2 commits into
PufferAI:4.0from
IlyaasK:fast-docker-build

Conversation

@IlyaasK

@IlyaasK IlyaasK commented Sep 2, 2026

Copy link
Copy Markdown

Fast Docker build: cache mounts, layer ordering, multi-stage Neovim (+1 bug fix)

Applies the principles from eblog's FastDocker to puffertank.dockerfile.

Changes

Cache mounts (BuildKit)--mount=type=cache so rebuilds reuse state across builds:

  • /root/.cache/uv → the ~3GB of cu130 torch wheels download once, not on every layer invalidation
  • /root/.cache/pufferexperiments.zip baseline download survives rebuilds
  • /var/cache/apt + /var/lib/apt → package lists/debs shared across builds
  • /root/.ccache (was already present)

Layer ordering: least → most frequently changed

  • COPY init.vim (was line 29) and COPY entrypoint.sh (was line 59) moved to the end. Previously, editing your vimrc invalidated the nsight, torch, and pufferlib layers — a multi-GB re-download per config tweak. Now a vimrc edit rebuilds only the final ~0s COPY layer.
  • ARG NEOVIM_REF / PUFFERLIB_REF / PUFFERAI_REF let you refresh git-clone layers with --build-arg instead of editing the file (Docker caches git clone layers forever since it never re-checks the remote). Defaults unchanged: master / 4.0 / 4.0.

Multi-stage build (ship the pizza, not the oven)

  • Neovim now builds in a nvim-builder stage with CMAKE_INSTALL_PREFIX=/opt/nvim; the final image copies only the installed runtime. Drops the nvim source tree + build artifacts (~1GB) and cmake/ninja/gettext/unzip from the final image.
  • make -j$(nproc) parallelizes the compile.

Smaller, granular layers

  • Two scattered apt-get install RUNs merged into one update && install layer (same package list); nsight stays on its own layer since it's large and version-bumped independently.
  • COPY --chmod=755 replaces the COPY+chmod pair.
  • Removed the trailing RUN apt-get clean — a cleanup in a new layer never shrinks the layers below it.

.dockerignore — rewritten as a whitelist: build context drops from the whole repo to 2 files (274 bytes measured with buildx --check), and the broken puffertank -> /puffertank symlink can no longer break context transfer.

Bug fix (separate commit)

Line 65 ends with \␣ (backslash + trailing space). The backslash escapes the space, so the shell sees an unescaped newline: a syntax error at && echo …. Every bashrc line from alias vim onward — the vim/diff/pip aliases, venv activation, cd pufferlib, the mesa env var — silently never applied in any image built from this revision. Continuations normalized; all 7 payloads byte-identical.

Validation

  • docker buildx build --check -f puffertank.dockerfile . → passes, no warnings (full frontend parse; base image not pulled).
  • The bashrc RUN body and the nested-quote alias diff line both execute cleanly under sh (the original fails with sh: syntax error near unexpected token '&&').

Not yet measured

Wall-clock build/rebuild timings are intentionally left out: this was prepared on an arm64 box without a GPU (no cu130 aarch64 torch wheels exist), so a fair measurement must happen on an amd64 + GPU machine. Expected effects once measured there:

  • cold build: nvim ~4x faster compile (-j), everything else roughly unchanged
  • warm rebuild after a config edit: was full nsight+torch+pufferlib re-download; now a sub-second COPY
  • image size: minus nvim source/build tree and cmake/ninja/gettext/unzip

Line 65 ends with backslash + trailing space. The backslash escapes
the space, so the shell sees an unescaped newline: every command from
'alias vim' onward (vim/diff/pip aliases, venv activation, cd
pufferlib, mesa env) was a syntax error and never made it into the
image.
Apply the fastdocker principles (eblog.fly.dev/fastdocker.html):

- Cache mounts for apt lists/debs, the uv wheel cache (~3GB torch wheels
  download once), ccache, and the experiments.zip baseline download.
- Layer ordering least-to-most-frequently-changed; the init.vim and
  entrypoint.sh COPYs move to the end so config edits no longer
  invalidate the nsight/torch/pufferlib layers.
- ARG NEOVIM_REF/PUFFERLIB_REF/PUFFERAI_REF so clone layers can be
  refreshed via --build-arg without editing the file (defaults
  unchanged: master/4.0/4.0).
- Neovim builds in a separate stage with CMAKE_INSTALL_PREFIX=/opt/nvim;
  the final image keeps only the installed runtime, dropping the source
  tree, build artifacts, and cmake/ninja/gettext/unzip. Adds -j(nproc).
- Merge scattered apt installs into one update+install layer; nsight
  stays on its own layer; COPY --chmod=755 replaces COPY+chmod; drop the
  no-op trailing 'apt-get clean' layer.
- .dockerignore whitelists the two COPY'd files: context drops from the
  whole repo to 274 bytes.
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