Spaces:
Running
Running
| # syntax=docker/dockerfile:1.6 | |
| # | |
| # Hugging Face Space Docker build for Mountain Waves. | |
| # | |
| # Two-stage build: the first stage has the Rust toolchain and produces a | |
| # manylinux-ish wheel of the compiled extension; the second stage is a slim | |
| # Python runtime that just installs the wheel + deps. This keeps the final | |
| # image under ~400 MB without needing cargo at runtime. | |
| # | |
| # HF Spaces routes external traffic to whatever port the container listens | |
| # on via `app_port` in README.md — we use 7860 (the HF default). | |
| # ---------- build stage: compile the Rust extension into a wheel ---------- | |
| # rayon 1.12 needs rustc ≥ 1.80; pin a modern stable image so the MSRV of the | |
| # transitive crate graph (rayon, pyo3, numpy) stays satisfied. | |
| FROM rust:1.82-slim AS build | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| python3 python3-pip python3-venv python3-dev \ | |
| build-essential pkg-config \ | |
| && rm -rf /var/lib/apt/lists/* | |
| RUN python3 -m pip install --break-system-packages "maturin==1.7.*" | |
| WORKDIR /src | |
| COPY Cargo.toml Cargo.lock pyproject.toml README.md ./ | |
| COPY src ./src | |
| COPY python ./python | |
| # Build a release wheel. -i python3 pins against the build image's 3.11 | |
| # interpreter; the runtime stage uses the same major.minor so the abi3 | |
| # wheel loads cleanly. | |
| RUN maturin build --release --out /wheels -i python3 | |
| # ---------- runtime stage: Python 3.11 slim + app + wheel ---------- | |
| FROM python:3.11-slim | |
| # libgomp1 is the OpenMP runtime rayon links against; eccodes pulls its own | |
| # shared libs in via the eccodeslib wheel, so nothing else is needed. | |
| RUN apt-get update && apt-get install -y --no-install-recommends \ | |
| libgomp1 \ | |
| && rm -rf /var/lib/apt/lists/* | |
| WORKDIR /app | |
| # Install the compiled Rust wheel + all runtime deps. Deps are listed | |
| # explicitly here instead of using `pip install .` so we don't drag maturin | |
| # and the build system into the runtime image. | |
| COPY --from=build /wheels /wheels | |
| RUN pip install --no-cache-dir /wheels/*.whl \ | |
| && pip install --no-cache-dir \ | |
| "numpy>=1.23" \ | |
| "scipy>=1.10" \ | |
| "dash>=2.16" \ | |
| "plotly>=5.20" \ | |
| "boto3>=1.28" \ | |
| "xarray>=2023.1" \ | |
| "cfgrib>=0.9.10" \ | |
| "eccodes>=2.37" \ | |
| "eccodeslib>=2.46" | |
| # HF Spaces runs the container as uid 1000 with /tmp as the only writable | |
| # directory by default. Cache dirs that libraries write to (plotly, boto3, | |
| # xdg) need to live somewhere the process can actually create files. | |
| ENV HOME=/tmp \ | |
| XDG_CACHE_HOME=/tmp/.cache \ | |
| MPLCONFIGDIR=/tmp/.mplconfig | |
| # Note: we intentionally do NOT copy python/ into the runtime image. The wheel | |
| # built in the previous stage contains both the pure-Python source and the | |
| # compiled _core*.so, installed into site-packages. If we also copied the | |
| # source tree here, run.py's sys.path.insert(0, "./python") would shadow the | |
| # wheel's copy with a _core-less source tree, and `from . import _core` would | |
| # fail with "partially initialized module" (HF deploy 2026-04-18). | |
| COPY run.py ./run.py | |
| # README.md is rendered inside the app's "Theory & About" modal at runtime. | |
| # Without this copy the modal falls back to a short placeholder. | |
| COPY README.md ./README.md | |
| EXPOSE 7860 | |
| CMD ["python", "run.py", "--host", "0.0.0.0", "--port", "7860"] | |