Docker Images
In the BioNemo Inference Runtime (BioIR) repository,
docker/Dockerfile is the single source of truth for every image this project
builds. docker/Makefile wraps it; .devcontainer/ consumes the dev target.
Building
deps— runtime and dev dependencies, no source.pyproject.tomlanduv.lockinvalidate its rolling CI build cache.dev—depsplus a user whose UID matches yours, for daily work on a GPU.docker/dev.shbuilds it withTAG=dev-<dirname>so each worktree gets its own image, then runs and enters the container.wheel— copies the source in with aCOPY ., so.dockerignorehas to stay accurate; builds the wheel and writes it to./dist.runtime— that wheel on a minimal CUDA base, for end-to-end tests and for deploying.submodules— builds nothing; runsgit submodule update --init --recursive.
The dependency stages install into the digest-pinned NGC Python interpreter.
They preserve its torch and Triton builds and omit the PyPI CUDA wheels pulled
by those packages. Every package layered on top comes from a hash-checked
uv.lock export. This image-specific policy retains the curated NGC framework
stack without allowing the remaining dependencies to drift.
Base images are overridable:
deps deliberately is not. It builds from the Dockerfile’s digest-pinned
default base, which is the compile identity the tracked CUBIN packs were built
against; a --build-arg there would let a rebased image claim it. BASE_TAG
still names the deps tag, though, so passing it renames the image without
changing its base — pass it only to label a build you know matches the pin.
CuTeDSL kernels ship precompiled. The default build also uses nvcc to compile
the source-visible ClaudeKit CUDA kernel. The toolkit version stamps the
wheel’s +cuXYZ local version; CUDA_TAG overrides that version tag, and
BUILD_JOBS caps the compile parallelism:
Below is the Dockerfile stages graph
Daily Development
The dev image carries the dependencies and no source: the checkout is
bind-mounted, so edits on the host are live and the image stays valid across
branches. Install the package once per container:
VS Code Dev Container
The Dev Containers extension’s “Reopen in Container” builds the
dev target through Compose and, on first create, runs that install plus
prek install. C++ IntelliSense stays empty until you have built once — the
install writes the compile_commands.json that .clangd reads. Delete build/
to force a clean configure.
Without VS Code
From anywhere in the worktree:
It builds the image, then starts or joins a long-lived container named after the
worktree directory, so a second terminal joins the shell already running.
docker/dev.sh --help lists the flags and the environment variables.
It mounts the same host directories the dev container does:
<cache> is bionemo-ir-dev under XDG_CACHE_HOME, or under ~/.cache when
that is unset, and is shared by every worktree; BIOIR_HOST_CACHE moves it.
The weight cache is mounted at the same absolute path on both sides, so a fetch
on the host and a fetch in the container fill the same one. BIOIR_CACHE is
read when the container is created — change it with docker/dev.sh --reset.
HF_TOKEN, HUGGING_FACE_HUB_TOKEN, BIOIR_NGC_ORG, BIOIR_NGC_TEAM and
NGC_API_KEY are passed through when set. GPUs are attached when the host has
the NVIDIA container runtime; BIOIR_GPUS overrides that (none, all,
"device=0").
Minimal Runtime Image
runtime installs the built wheel onto nvidia/cuda:*-base, adding gcc and
the Python headers for Triton JIT compilation.
The CUDA base supplies libcudart for the source-built ClaudeKit kernel.
The host driver supplies libcuda.so.1 through docker run --gpus.
The build checks that every other extension dependency resolves and rejects
CUDA math and JIT libraries outside this base’s supported closure.
runtime is used for testing and deploying the wheel with minimal image size.
To run folding with it, mount the data and weights inside the container, e.g:
Stage the weights first with scripts/fetch_weights.sh
BIOIR_KERNEL_CACHE_DIR must name a directory owned by the runtime user. Do
not place it on a filesystem writable by untrusted users. BioIR restricts the
CuTe DSL cache directory to mode 0700 and ignores cached objects it does not
own.