v1.6.0 container image grew 78MiB → 113MiB after pip-based Containerfile switch #29

Open
opened 2026-09-11 09:04:25 +01:00 by Hermes · 0 comments
Collaborator

Switching the Containerfile from the uv multi-stage build (distroless final image) to a single-stage python:3.14-slim + pip install build (part of #the python-packages PR / v1.6.0) grew the shipped image from 78MiB to 113MiB. Likely causes, roughly in order of impact:

  1. Base image is bigger. gcr.io/distroless/cc-debian13:nonroot is just libc + minimal C runtime libs (no shell/package manager). python:3.14-slim is a full slim Debian install (apt/dpkg, full Python stdlib, libssl/libsqlite/zlib, etc.) — typically ~45-55MiB before installing anything. Probably the single biggest contributor.

  2. Lost the multi-stage build. The old Containerfile built with uv in a throwaway stage and copied only /usr/share/uv (managed Python) + /app (locked, --no-editable, --no-dev venv) into the distroless final image — no pip/setuptools/wheel/build backend ever reached the final layer. The new Containerfile installs directly with pip in the image that ships, so pip/setuptools/wheel and any build-time deps now stay resident in site-packages.

  3. pip cache isn't cleared. pip download and pip install populate ~/.cache/pip (/root/.cache/pip) by default. The Containerfile only removes /tmp/pkg (the downloaded wheel dir) — the pip cache itself persists in the layer. Adding --no-cache-dir to both pip calls (or ENV PIP_NO_CACHE_DIR=1) should trim this.

Suggested fix: go back to a multi-stage build — pip install/pip download into a python:3.14-slim (or similar) builder stage, then COPY --from=build /app /app (or --target=/app) into a slim/distroless runtime stage, dropping pip/setuptools/apt metadata/cache from the final image. Should claw back most of the ~35MiB delta while keeping the simpler Forgejo-PyPI-based install flow.

Revisiting later — filing for tracking.

Switching the Containerfile from the uv multi-stage build (distroless final image) to a single-stage `python:3.14-slim` + `pip install` build (part of #the python-packages PR / v1.6.0) grew the shipped image from 78MiB to 113MiB. Likely causes, roughly in order of impact: 1. **Base image is bigger.** `gcr.io/distroless/cc-debian13:nonroot` is just libc + minimal C runtime libs (no shell/package manager). `python:3.14-slim` is a full slim Debian install (apt/dpkg, full Python stdlib, libssl/libsqlite/zlib, etc.) — typically ~45-55MiB before installing anything. Probably the single biggest contributor. 2. **Lost the multi-stage build.** The old Containerfile built with uv in a throwaway stage and copied only `/usr/share/uv` (managed Python) + `/app` (locked, `--no-editable`, `--no-dev` venv) into the distroless final image — no pip/setuptools/wheel/build backend ever reached the final layer. The new Containerfile installs directly with pip in the image that ships, so pip/setuptools/wheel and any build-time deps now stay resident in `site-packages`. 3. **pip cache isn't cleared.** `pip download` and `pip install` populate `~/.cache/pip` (`/root/.cache/pip`) by default. The Containerfile only removes `/tmp/pkg` (the downloaded wheel dir) — the pip cache itself persists in the layer. Adding `--no-cache-dir` to both pip calls (or `ENV PIP_NO_CACHE_DIR=1`) should trim this. **Suggested fix:** go back to a multi-stage build — `pip install`/`pip download` into a `python:3.14-slim` (or similar) builder stage, then `COPY --from=build /app /app` (or `--target=/app`) into a slim/distroless runtime stage, dropping pip/setuptools/apt metadata/cache from the final image. Should claw back most of the ~35MiB delta while keeping the simpler Forgejo-PyPI-based install flow. Revisiting later — filing for tracking.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
cpressland/rabbitdb#29
No description provided.