Trim ~350MB of unreachable payload from the backend image

The image was 2.45GB, of which the venv is 1.73GB. The build was already
multi-stage and already installed CPU-only torch, so the remaining weight was
not build tooling - it was payload inside the installed packages that the
running service can never execute.

Removed in the build stage, before the runtime stage copies /opt/venv, so the
bytes never enter the final image:

  - bundled test suites (~237MB; torch/test is 83MB, pandas/tests 40MB)
  - torch/include (62MB), C++ headers for compiling against libtorch
  - torch/bin (50MB), gtest binaries and protoc; torch_shm_manager is kept

pytest and httpx2 move to requirements-dev.txt: the image copies app/, cli/,
scripts/, data/ and serve.py, never tests/, so the test stack was unusable
there regardless.

sympy was checked and deliberately kept - 'import sentence_transformers' does
pull it in through torch.fx, so removing it would break embeddings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-16 09:52:52 +05:30
parent dce2405e50
commit 5e373ea20c
4 changed files with 46 additions and 8 deletions

View File

@@ -37,6 +37,32 @@ RUN python -m venv /opt/venv \
--index-url https://download.pytorch.org/whl/cpu torch \
&& /opt/venv/bin/pip install --no-cache-dir -r requirements.txt
# Strip payload the running service can never execute. Doing this in the build
# stage is what makes it count: the runtime stage copies /opt/venv as one layer,
# so anything deleted after that COPY would still occupy space in the layer
# below it. Deleting it here means the bytes are never in the final image.
#
# Measured on this image, the venv was 1.65GB, and this removes ~350MB of it:
#
# - Bundled test suites (~237MB, of which torch/test alone is 83MB). Every
# scientific wheel ships its own; pandas/tests is 40MB. Matched on exactly
# `tests`/`test` so numpy.testing and sklearn.utils._testing - which ARE
# imported by library code at runtime - are left alone.
# - torch/include (62MB): C++ headers, needed only to COMPILE an extension
# against libtorch. Nothing here does; torch is used through Python.
# - torch/bin (50MB): C++ gtest binaries (test_api is 15MB, test_jit 13.5MB)
# plus a protoc. torch_shm_manager is the one real program in there - it
# brokers shared-memory tensors between processes - so it is kept.
#
# Verified against this app rather than assumed: sympy IS pulled in by `import
# sentence_transformers` (via torch.fx), so it stays despite being 80MB and
# looking like a pure-math dependency nothing here would want.
RUN set -eux; \
SP=/opt/venv/lib/python3.11/site-packages; \
find "$SP" -type d \( -name tests -o -name test \) -prune -exec rm -rf {} +; \
rm -rf "$SP/torch/include"; \
find "$SP/torch/bin" -type f ! -name torch_shm_manager -delete
# ---- Runtime stage ----
FROM python:3.11-slim AS runtime

View File

@@ -32,7 +32,7 @@ It does **not** start Postgres or Ollama for you - it reports them via
cd backend
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
pip install -r requirements.txt -r requirements-dev.txt # -dev is pytest only
cp .env.example .env # then edit DB_PASSWORD etc.
@@ -198,7 +198,8 @@ backend/
├── cli/ingest_brand.py # CLI: ingest one brand end-to-end
├── scripts/seed_sample_data.py # load bundled sample catalogs (no LLM needed)
├── data/seed_catalogs/*.json # bundled sample catalogs (Parle, Cadbury, ...)
└── requirements.txt
├── requirements.txt
└── requirements-dev.txt
```
## Running tests

14
requirements-dev.txt Normal file
View File

@@ -0,0 +1,14 @@
# Test-only dependencies, kept out of requirements.txt so the Docker image does
# not ship them - the container has no tests/ directory to run anyway (the
# Dockerfile copies app/, cli/, scripts/, data/ and serve.py, nothing else).
#
# For development, install both files:
# pip install -r requirements.txt -r requirements-dev.txt
pytest>=8.3.3
# Starlette's TestClient deprecates the httpx 0.x backend and emits a
# StarletteDeprecationWarning without this. pytest.ini turns warnings into
# errors, so it is a hard requirement of the suite, not a nicety. Test-only:
# the application itself uses the `httpx` pinned in requirements.txt.
httpx2>=2.10.0

View File

@@ -76,9 +76,6 @@ scipy>=1.13.1
joblib>=1.4.2
# --- Dev/test tooling ---
pytest>=8.3.3
# Starlette's TestClient deprecates the httpx 0.x backend and emits a
# StarletteDeprecationWarning without this. pytest.ini turns warnings into
# errors, so it is a hard requirement of the suite, not a nicety. Test-only:
# the application itself uses the `httpx` pinned above.
httpx2>=2.10.0
# Moved to requirements-dev.txt so the Docker image does not carry the test
# stack it can never run. To work on this project, install both:
# pip install -r requirements.txt -r requirements-dev.txt