From e52277e5b7ecd92e06053ea885405b289ee14182 Mon Sep 17 00:00:00 2001 From: IlyaasK <86218345+IlyaasK@users.noreply.github.com> Date: Tue, 1 Sep 2026 22:58:08 -0400 Subject: [PATCH 1/2] Fix bashrc line-continuation syntax error 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. --- puffertank.dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/puffertank.dockerfile b/puffertank.dockerfile index 7badb7e..ca86acd 100644 --- a/puffertank.dockerfile +++ b/puffertank.dockerfile @@ -62,7 +62,7 @@ ENTRYPOINT ["/root/entrypoint.sh"] # Bashrc RUN echo "export PS1=$''" >> ~/.bashrc \ - && echo "alias vim='/usr/bin/nvim'" >> ~/.bashrc \ + && echo "alias vim='/usr/bin/nvim'" >> ~/.bashrc \ && echo "alias diff='diff --color --palette=':ad=36:de=31:ln=33''" >> ~/.bashrc \ && echo "alias pip='uv pip'" >> ~/.bashrc \ && echo ". /puffertank/venv/bin/activate" >> ~/.bashrc \ From b3b930b1ba3bc79512d329d797a8eaed76360e65 Mon Sep 17 00:00:00 2001 From: IlyaasK <86218345+IlyaasK@users.noreply.github.com> Date: Tue, 1 Sep 2026 22:58:24 -0400 Subject: [PATCH 2/2] Optimize Docker build: cache mounts, layer order, multi-stage nvim 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. --- .dockerignore | 12 ++--- puffertank.dockerfile | 123 +++++++++++++++++++++++++----------------- 2 files changed, 80 insertions(+), 55 deletions(-) diff --git a/.dockerignore b/.dockerignore index 4042bca..bdcb1e7 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,7 +1,5 @@ -.git -.gitignore -Dockerfile* -docker-compose* -README.md -LICENSE -.vscode \ No newline at end of file +# Only the two files the image COPYs belong in the build context. +# Everything else (scripts, docs, .git, the broken puffertank symlink) is noise. +* +!entrypoint.sh +!init.vim diff --git a/puffertank.dockerfile b/puffertank.dockerfile index ca86acd..3b1c75e 100644 --- a/puffertank.dockerfile +++ b/puffertank.dockerfile @@ -1,73 +1,100 @@ +# syntax=docker/dockerfile:1 + +# --------------------------------------------------------------------------- +# Stage 0: build Neovim from source (latest master). The final image only +# copies the installed runtime (/opt/nvim) -- not cmake/ninja/gettext, the +# source tree, or the build artifacts. +# --------------------------------------------------------------------------- +FROM nvcr.io/nvidia/cuda:13.0.2-cudnn-devel-ubuntu24.04 AS nvim-builder +ARG DEBIAN_FRONTEND=noninteractive +ARG NEOVIM_REF=master + +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && apt-get install -y --no-install-recommends ninja-build gettext cmake unzip + +RUN git clone --single-branch --depth=1 --branch ${NEOVIM_REF} https://github.com/neovim/neovim \ + && cd neovim \ + && make CMAKE_BUILD_TYPE=Release CMAKE_INSTALL_PREFIX=/opt/nvim -j$(nproc) \ + && make install + +# --------------------------------------------------------------------------- +# Stage 1: the dev container. Layers are ordered from least-frequently to +# most-frequently changed, so expensive work (apt, nvim, torch, pufferlib) +# stays cached while config files churn. Cache mounts survive rebuilds. +# --------------------------------------------------------------------------- FROM nvcr.io/nvidia/cuda:13.0.2-cudnn-devel-ubuntu24.04 ARG DEBIAN_FRONTEND=noninteractive -RUN mkdir -p /puffertank WORKDIR /puffertank -# Core system packages -# Custom installs without the cudnn base also need libnccl2 libnccl-dev -RUN apt-get update && apt-get install -y curl wget sudo git build-essential clang +# Core system packages. +# Custom installs without the cudnn base also need libnccl2 libnccl-dev. +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && apt-get install -y curl wget sudo git build-essential clang \ + htop gdb tmux psmisc llvm ccache \ + sqlite3 \ + libomp-dev libglfw3 libgl1-mesa-dev python3.12-dev -# UV venv +# Nsight Systems for profiling (own layer: large, and version-bumped on its own). +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + apt-get update \ + && apt-get install -y --no-install-recommends nsight-systems-2025.6.3 + +# UV venv + pynvim RUN curl -LsSf https://astral.sh/uv/install.sh | sh \ && . $HOME/.local/bin/env \ - && uv venv --python 3.12 --prompt 🐡 venv - -# Neovim (btw) -RUN . $HOME/.local/bin/env \ + && uv venv --python 3.12 --prompt 🐡 venv \ && . venv/bin/activate \ - && apt-get install -y ninja-build gettext cmake unzip \ - && git clone --single-branch --depth=1 https://github.com/neovim/neovim \ - && cd neovim \ - && make CMAKE_BUILD_TYPE=Release \ - && make install \ - && ln -s /usr/local/bin/nvim /usr/bin/nvim \ - && . $HOME/.local/bin/env \ - && uv pip install pynvim \ - && sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' -# My personal config -COPY init.vim /root/.config/nvim/init.vim - -RUN apt-get install -y\ - htop gdb tmux psmisc llvm ccache \ - sqlite3 \ - libomp-dev libglfw3 libgl1-mesa-dev python3.12-dev + && uv pip install pynvim -# Nsight Systems for profiling -RUN apt-get install -y --no-install-recommends nsight-systems-2025.6.3 +# Neovim runtime, built in the stage above +COPY --from=nvim-builder /opt/nvim /opt/nvim +RUN ln -s /opt/nvim/bin/nvim /usr/bin/nvim \ + && sh -c 'curl -fLo "${XDG_DATA_HOME:-$HOME/.local/share}"/nvim/site/autoload/plug.vim --create-dirs https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim' -# PyTorch + uv env -RUN . $HOME/.local/bin/env \ +# PyTorch. The uv cache mount persists across builds: ~3GB of wheels download once. +RUN --mount=type=cache,target=/root/.cache/uv \ + . $HOME/.local/bin/env \ && . venv/bin/activate \ && uv pip install torch --index-url https://download.pytorch.org/whl/cu130 -# PufferLib + docs + 20k baseline experiments viewable with Constellation -RUN --mount=type=cache,target=/root/.ccache . $HOME/.local/bin/env \ - && git clone https://github.com/pufferai/pufferlib --branch 4.0 \ - && git clone https://github.com/pufferai/puffer.ai --branch 4.0 \ +# PufferLib + docs + 20k baseline experiments viewable with Constellation. +# Bump PUFFERLIB_REF / PUFFERAI_REF (or pass --build-arg) to refresh this layer. +ARG PUFFERLIB_REF=4.0 +ARG PUFFERAI_REF=4.0 +RUN --mount=type=cache,target=/root/.ccache \ + --mount=type=cache,target=/root/.cache/uv \ + --mount=type=cache,target=/root/.cache/puffer \ + . $HOME/.local/bin/env \ + && git clone https://github.com/pufferai/pufferlib --branch ${PUFFERLIB_REF} \ + && git clone https://github.com/pufferai/puffer.ai --branch ${PUFFERAI_REF} \ && . venv/bin/activate \ && cd pufferlib \ && uv pip install -e . \ && bash build.sh breakout \ - && curl -L -o experiments.zip https://github.com/PufferAI/PufferLib/releases/download/experiments/experiments.zip \ - && unzip -q experiments.zip \ - && rm experiments.zip \ + && curl -L -o /root/.cache/puffer/experiments.zip https://github.com/PufferAI/PufferLib/releases/download/experiments/experiments.zip \ + && unzip -q /root/.cache/puffer/experiments.zip \ && python constellation/cache_data.py --full \ && bash build.sh constellation --fast -# Run on container startup -COPY entrypoint.sh /root/entrypoint.sh -RUN chmod +x /root/entrypoint.sh -ENTRYPOINT ["/root/entrypoint.sh"] - # Bashrc RUN echo "export PS1=$''" >> ~/.bashrc \ - && echo "alias vim='/usr/bin/nvim'" >> ~/.bashrc \ - && echo "alias diff='diff --color --palette=':ad=36:de=31:ln=33''" >> ~/.bashrc \ - && echo "alias pip='uv pip'" >> ~/.bashrc \ - && echo ". /puffertank/venv/bin/activate" >> ~/.bashrc \ - && echo "cd /puffertank/pufferlib" >> ~/.bashrc \ - && echo "export __GLX_VENDOR_LIBRARY_NAME=mesa" >> ~/.bashrc + && echo "alias vim='/usr/bin/nvim'" >> ~/.bashrc \ + && echo "alias diff='diff --color --palette=':ad=36:de=31:ln=33''" >> ~/.bashrc \ + && echo "alias pip='uv pip'" >> ~/.bashrc \ + && echo ". /puffertank/venv/bin/activate" >> ~/.bashrc \ + && echo "cd /puffertank/pufferlib" >> ~/.bashrc \ + && echo "export __GLX_VENDOR_LIBRARY_NAME=mesa" >> ~/.bashrc + +# Config files last: the only COPY steps, so nothing above them is invalidated. +COPY --chmod=755 entrypoint.sh /root/entrypoint.sh +COPY init.vim /root/.config/nvim/init.vim -RUN apt-get clean +# Run on container startup +ENTRYPOINT ["/root/entrypoint.sh"] CMD ["/bin/bash"]