Strip symbol tables from the compiled extensions in the Docker image - #2439
Merged
Conversation
…tray docs/examples Signed-off-by: Stijn van Houwelingen <teadrinkingprogrammer@proton.me>
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 <felix@seita.nl>
Documentation build overview
|
Signed-off-by: F.N. Claessen <felix@seita.nl> # Conflicts: # Dockerfile # documentation/changelog.rst
This was referenced Aug 25, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
This PR reduces the size of the FlexMeasures Docker image by stripping symbol tables from compiled Python extension modules during the builder stage, so only the stripped artifacts are copied into the runtime image. It also updates the changelog entry (stacked on #2438) to reflect the additional image-size reduction.
Changes:
- Strip symbol tables from all
*.so/*.so.*files inside${VIRTUAL_ENV}during the builder stage to reduce final runtime image size. - Expand the existing Infrastructure / Support changelog entry (from #2438) to include symbol-table stripping and link both PRs.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| Dockerfile | Add builder-stage strip --strip-unneeded pass over shared objects to shrink the runtime image |
| documentation/changelog.rst | Expand the existing Docker image shrinking entry to include symbol-table stripping and link PR #2439 |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…pping 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 <felix@seita.nl>
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 <felix@seita.nl>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Strips the symbol tables from the compiled extensions in the image. Most wheels ship them unstripped; nothing uses them at runtime.
Shares the changelog entry introduced by #2438 rather than adding one of its own, since both shrink the image through the builder stage. #2440 is stacked on this and widens the same entry again.
What changed
One
RUNin the builder stage, after the existingrm -rfof sktime's stray payloads:Placement matters. Because the runtime stage only does
COPY --from=builder ${VIRTUAL_ENV}, the unstripped copies never reach a layer that ships — stripping in the runtime stage instead would grow the image, since the fat layer would still sit underneath.strip --strip-unneededkeeps everything dynamic linking needs, which is why the extensions stay loadable.The explicit
stripcheck came out of review:binutilsonly reaches this stage incidentally, as a transitive of thegccinstall above. Without the check, the trailing|| truewould swallowstrip: not foundand turn the whole step into a no-op, growing the image back by ~130 MB with nothing failing and CI staying green. The|| truestays on thefind, where it is wanted — tolerating individual files strip cannot handle.Measured
main(with #2438)Against
mainbefore #2438 the same step was worth 132.8 MB. The 2.8 MB difference is symbol tables in dev-only packages that--no-devalready removes, mostly mypy's mypyc extensions — the two changes overlap slightly, so the numbers should not be added.Where it comes from, measured across all 726 shared objects belonging to locked distributions:
.sobytesHow to test
docker build -t fm-strip . docker run --rm fm-strip flexmeasures --versionSmoke-tested on the built image: the CLI starts (and stops at the missing
SQLALCHEMY_DATABASE_URI, as expected without a database), andflexmeasures,timely_beliefs,openturns,scipy,numpy,pandas,sklearn,lightgbm,dartsandstatsmodelsall import. openturns got the closest look, being both the biggest saver and a C++/SWIG library with a large ABI surface:Normal,UserDefined,NormalCopula,IndependentCopula,JointDistributionandMixtureall behave identically stripped.The guard was checked on
/bin/sh, the builder's shell, in both directions: withstrippresent it exits 0 and strips; withstripoff the PATH it prints the message and exits 1.Further Improvements
The bigger remaining items are about what is in the image rather than how it is packed:
dartsand its chain (shap/pyod→numba→llvmlite) is ~310 MB,openturns~250 MB,vl-convert-python88 MB. Ranked with their user-facing costs in #2437.Related Items
Part of #2437. #2440 stacks on this.
Sign-off
🤖 Generated with Claude Code