From 0b697c79b822eaaaba5a16dc256447b3bbddcb20 Mon Sep 17 00:00:00 2001 From: Stijn van Houwelingen Date: Tue, 25 Aug 2026 09:48:53 +0200 Subject: [PATCH 1/6] fix: shrink docker image by excluding dev deps and pruning sktime's stray docs/examples Signed-off-by: Stijn van Houwelingen --- Dockerfile | 9 +++++++-- documentation/changelog.rst | 3 ++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index c83ffd7910..1e1e3d0cae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,10 +23,11 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ WORKDIR /app # Sync dependencies without installing the project itself (creates .venv) +# --no-dev excludes the dev dependency-group (mypy, black, flake8, ...). RUN --mount=type=cache,target=/root/.cache/uv \ --mount=type=bind,source=uv.lock,target=uv.lock \ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ - uv sync --locked --no-install-project + uv sync --locked --no-install-project --no-dev # Ensure subsequent commands use the virtual environment ENV VIRTUAL_ENV=/app/.venv \ @@ -45,12 +46,16 @@ COPY .flaskenv wsgi.py ./ ARG FLEXMEASURES_VERSION= RUN --mount=type=cache,target=/root/.cache/uv \ SETUPTOOLS_SCM_PRETEND_VERSION="${FLEXMEASURES_VERSION}" \ - uv sync --frozen --reinstall-package flexmeasures + uv sync --frozen --reinstall-package flexmeasures --no-dev # Install gunicorn separately since it's not a dependency of the project RUN --mount=type=cache,target=/root/.cache/uv \ uv pip install gunicorn==25.0.3 +# sktime (and its scikit-base dependency) ship docs/ and examples/ as stray top-level directories. See: https://github.com/sktime/sktime/issues/10891 +RUN rm -rf "${VIRTUAL_ENV}"/lib/python*/site-packages/docs \ + "${VIRTUAL_ENV}"/lib/python*/site-packages/examples + # Use a separate runtime image to run the code FROM python:${PYTHON_VERSION}-slim-${DEBIAN_VERSION} AS runtime diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 7826b0f7cd..4a67cf57a6 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -13,6 +13,7 @@ New features Infrastructure / Support ------------------------- +* Shrink the Docker image by excluding dev-only dependencies and pruning stray ``docs``/``examples`` payloads bundled by ``sktime``/``scikit-base`` (issue: https://github.com/sktime/sktime/issues/10891) [see `PR #XXXX `_] Bugfixes ----------- @@ -1425,7 +1426,7 @@ Infrastructure / Support .. warning:: The API endpoint (`[POST] /sensors/(id)/schedules/trigger `_) to make new schedules will (in v0.13) sunset the storage flexibility parameters (they move to the ``flex-model`` parameter group), as well as the parameters describing other sensors (they move to ``flex-context``). .. warning:: The CLI command ``flexmeasures monitor tasks`` has been deprecated (it's being renamed to ``flexmeasures monitor last-run``). The old name will be sunset in version 0.13. - + .. warning:: The CLI command ``flexmeasures add schedule`` has been renamed to ``flexmeasures add schedule for-storage``. The old name will be sunset in version 0.13. From 6429a11a9f696e2bccc340bc52d1d1b4360cd61e Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Tue, 25 Aug 2026 18:56:22 +0200 Subject: [PATCH 2/6] docs: fill in the PR number in the changelog entry Context: - Review on #2438: the entry still carried the XXXX placeholder, in the label and the URL Change: - Pointed both at PR #2438 Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 4a67cf57a6..70a4767d86 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -13,7 +13,7 @@ New features Infrastructure / Support ------------------------- -* Shrink the Docker image by excluding dev-only dependencies and pruning stray ``docs``/``examples`` payloads bundled by ``sktime``/``scikit-base`` (issue: https://github.com/sktime/sktime/issues/10891) [see `PR #XXXX `_] +* Shrink the Docker image by excluding dev-only dependencies and pruning stray ``docs``/``examples`` payloads bundled by ``sktime``/``scikit-base`` (issue: https://github.com/sktime/sktime/issues/10891) [see `PR #2438 `_] Bugfixes ----------- From 46f06e13b6a8184efdf6808ce0bb98527ab8659e Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Tue, 25 Aug 2026 18:57:53 +0200 Subject: [PATCH 3/6] docker: strip symbol tables from the compiled extensions Context: - Most wheels ship their compiled extensions unstripped. The symbol tables and debug info they carry are never used at runtime, and openturns alone accounts for over a fifth of the weight Change: - Strip the shared objects in the builder stage, so only the stripped virtual environment is copied into the runtime image and no layer keeps the fat copy - --strip-unneeded retains everything dynamic linking needs, so the extensions stay loadable Signed-off-by: F.N. Claessen --- Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Dockerfile b/Dockerfile index 1e1e3d0cae..c1ec6094c9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,6 +56,13 @@ RUN --mount=type=cache,target=/root/.cache/uv \ RUN rm -rf "${VIRTUAL_ENV}"/lib/python*/site-packages/docs \ "${VIRTUAL_ENV}"/lib/python*/site-packages/examples +# Most wheels ship their compiled extensions unstripped, carrying symbol tables and debug +# info that nothing needs at runtime. Dropping them here (in the builder, so only the +# stripped result reaches the runtime image) is worth ~130 MB, over a fifth of it openturns. +# --strip-unneeded keeps everything dynamic linking uses, so the extensions stay loadable. +RUN find "${VIRTUAL_ENV}" \( -name '*.so' -o -name '*.so.*' \) -type f \ + -exec strip --strip-unneeded {} + 2>/dev/null || true + # Use a separate runtime image to run the code FROM python:${PYTHON_VERSION}-slim-${DEBIAN_VERSION} AS runtime From 6987c0d6f2f77acddec8004b6e93119c487f1993 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Tue, 25 Aug 2026 19:15:41 +0200 Subject: [PATCH 4/6] docs: widen the Docker image entry to cover the stripping Context: - Both PRs shrink the image through the builder stage, so one entry reads better than two Change: - Expanded the entry #2438 introduced to mention the symbol stripping, and appended PR #2439 to its reference list Signed-off-by: F.N. Claessen --- documentation/changelog.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/changelog.rst b/documentation/changelog.rst index 70a4767d86..aa9d8f298b 100644 --- a/documentation/changelog.rst +++ b/documentation/changelog.rst @@ -13,7 +13,7 @@ New features Infrastructure / Support ------------------------- -* Shrink the Docker image by excluding dev-only dependencies and pruning stray ``docs``/``examples`` payloads bundled by ``sktime``/``scikit-base`` (issue: https://github.com/sktime/sktime/issues/10891) [see `PR #2438 `_] +* Shrink the Docker image by excluding dev-only dependencies, pruning stray ``docs``/``examples`` payloads bundled by ``sktime``/``scikit-base`` (issue: https://github.com/sktime/sktime/issues/10891), and stripping the symbol tables that the compiled extensions ship with [see `PR #2438 `_ and `PR #2439 `_] Bugfixes ----------- From f1b5ac9677fc608ef23d6ebc8856c1fa1ab959f3 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Tue, 25 Aug 2026 23:23:16 +0200 Subject: [PATCH 5/6] docker: fail the build when strip is missing, instead of silently skipping Context: - Review: the trailing '|| true' also swallows 'strip: not found', which would turn this step into a no-op and let the image quietly grow back by ~130 MB with nothing failing. binutils arrives via gcc today, but that is incidental Change: - Check for strip up front and exit 1 with a message naming binutils - Kept '|| true' on the find, which is there to tolerate individual files that strip cannot handle - Also reworded the size note, which read ungrammatically Signed-off-by: F.N. Claessen --- Dockerfile | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index c1ec6094c9..d75d39404d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -58,9 +58,15 @@ RUN rm -rf "${VIRTUAL_ENV}"/lib/python*/site-packages/docs \ # Most wheels ship their compiled extensions unstripped, carrying symbol tables and debug # info that nothing needs at runtime. Dropping them here (in the builder, so only the -# stripped result reaches the runtime image) is worth ~130 MB, over a fifth of it openturns. -# --strip-unneeded keeps everything dynamic linking uses, so the extensions stay loadable. -RUN find "${VIRTUAL_ENV}" \( -name '*.so' -o -name '*.so.*' \) -type f \ +# stripped result reaches the runtime image) is worth ~130 MB, over a fifth of that from +# openturns. --strip-unneeded keeps everything dynamic linking uses, so the extensions stay +# loadable. strip comes from binutils, which the gcc install above pulls in; we check for it +# rather than let the trailing `|| true` turn a missing binutils into a silent 130 MB +# regression. That `|| true` is only there to tolerate individual files strip cannot handle. +RUN command -v strip > /dev/null || { \ + echo "strip not found: the builder stage needs binutils" >&2; exit 1; \ + }; \ + find "${VIRTUAL_ENV}" \( -name '*.so' -o -name '*.so.*' \) -type f \ -exec strip --strip-unneeded {} + 2>/dev/null || true # Use a separate runtime image to run the code From 2554df2a22e02f61f4b556a689b4e6f0669a7569 Mon Sep 17 00:00:00 2001 From: "F.N. Claessen" Date: Wed, 26 Aug 2026 10:53:02 +0200 Subject: [PATCH 6/6] docker: break the strip comment only after punctuation Context: - The repo convention is that each physical line of a comment ends at punctuation, so review comments and text search stay stable Change: - Reflowed the comment block, and tightened it from seven lines to five Signed-off-by: F.N. Claessen --- Dockerfile | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/Dockerfile b/Dockerfile index d75d39404d..01b2a352d9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -56,13 +56,11 @@ RUN --mount=type=cache,target=/root/.cache/uv \ RUN rm -rf "${VIRTUAL_ENV}"/lib/python*/site-packages/docs \ "${VIRTUAL_ENV}"/lib/python*/site-packages/examples -# Most wheels ship their compiled extensions unstripped, carrying symbol tables and debug -# info that nothing needs at runtime. Dropping them here (in the builder, so only the -# stripped result reaches the runtime image) is worth ~130 MB, over a fifth of that from -# openturns. --strip-unneeded keeps everything dynamic linking uses, so the extensions stay -# loadable. strip comes from binutils, which the gcc install above pulls in; we check for it -# rather than let the trailing `|| true` turn a missing binutils into a silent 130 MB -# regression. That `|| true` is only there to tolerate individual files strip cannot handle. +# Most wheels ship their compiled extensions unstripped, carrying symbol tables and debug info that nothing needs at runtime. +# Stripping them here keeps ~130 MB out of the runtime image, which copies only the result of this stage. +# --strip-unneeded leaves everything that dynamic linking uses, so the extensions stay loadable. +# binutils only reaches this stage as a transitive of the gcc install above, so check for strip explicitly: +# the trailing `|| true` is there for individual files strip cannot handle, and would otherwise hide a missing binutils. RUN command -v strip > /dev/null || { \ echo "strip not found: the builder stage needs binutils" >&2; exit 1; \ }; \