Skip to content

perf(docker): uv.lock-pinned venv, ~490 MB smaller image; declare packaging - #965

Merged
ajslater merged 2 commits into
developfrom
docker-slim
Oct 5, 2026
Merged

ajslater merged 2 commits into
developfrom
docker-slim

Conversation

@ajslater

@ajslater ajslater commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fix: codex/version.py has imported packaging since v2.2.10 but codex never declared it. A fresh codex==2.5.1 PyPI install crashes on import; the Docker image only worked because the builder's tooling leaked it in. Adds packaging>=24.0.
  • Docker: runtime deps now go into a venv at /opt/codex, pinned from uv.lock, and only that venv is copied into final (it used to copy the builder's whole /usr/local: node, uv, poetry, pipenv).
  • apt: final installs only curl libstdc++6 unrar. ruamel.yaml.clib was read by apt as a regex and installed Debian's whole python3.13. The image codec libs were unused because the Pillow/PyYAML wheels bundle their own.
  • Bytecode kept: it's compiled at install instead of purged, since abc can't write .pyc. import codex.asgi as abc goes from 3.3 s to 1.1 s.
  • Locales: non-English locales and pycountry's gettext data are dropped (LANGUAGE_CODE = "en-us", no LocaleMiddleware).
  • tests/test_dockerfile.py guards the apt list, regex-trap names, the venv-only copy and kept bytecode. .dockerignore re-admits Dockerfile so the test runs in CI.
arm64, uncompressed before after
image 1,380 MB 889 MB
runtime COPY layer 841 MB 513 MB
apt layer 66.7 MB 14.9 MB
Debian python3 yes no

About 208 MB more (scipy/numpy/pywt via imagehash) goes away once codex moves to comicbox 5.3.0, which replaces imagehash with a bit-identical pure-Python pHash.

Test plan

  • make fix lint ty test on macOS (hadolint + dockerfmt included): 1580 passed, 962 frontend passed
  • Same make build-choices lint test inside the rebuilt codex-ci image
  • docker buildx build --platform linux/amd64,linux/arm64 builds; the build-time smoke import passes on both
  • Container with PUID/PGID: /health is 200, a CBZ/CBR/PDF library imports, and covers and first pages are byte-identical to the old image's
  • DRF validation messages still render in English, including with Accept-Language: de
  • tests/test_dockerfile.py fails all 4 checks against the old Dockerfile

🤖 Generated with Claude Code

ajslater and others added 2 commits October 5, 2026 01:00
codex/version.py has imported packaging.version since 446cab8 (v2.2.10),
but packaging was never a dependency and nothing in the runtime closure
pulls it in. Installs only worked where something else had dragged it in:
the Docker image got it from the builder's pip/poetry tooling. A fresh
`uv pip install codex==2.5.1` crashes on import with
ModuleNotFoundError: No module named 'packaging'.

An AST scan of every import under codex/ against a runtime-only venv finds
nothing else missing (icecream and schema_graph are dev-guarded).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The final image was python-debian plus `COPY --from=wheel-installer
/usr/local /usr/local`, which shipped the whole nikolaik builder: node,
npm, uv, poetry and pipenv (~330 MB), and replaced python-debian's own
interpreter and stdlib.

- Runtime deps now install into /opt/codex, a venv on python-debian's
  interpreter, pinned from uv.lock via `uv export` instead of re-resolved
  from pyproject ranges. Only that venv is copied into final. PATH gets
  /opt/codex/bin so `docker exec codex python` still works.
- The apt install of `ruamel.yaml.clib` was parsed as a regex and
  installed python3-ruamel.yaml.clib plus Debian's entire python3.13.
  The image codec libraries were dead weight too (the Pillow and PyYAML
  wheels bundle their own). final installs only curl, libstdc++6 and unrar.
- Bytecode is compiled at install time instead of purged. The app runs as
  abc, which can't write .pyc files, so every process recompiled on
  import: `import codex.asgi` as abc drops from 3.3 s to 1.1 s.
- pycountry's gettext locales and every non-English Django/allauth/DRF
  locale are removed: LANGUAGE_CODE is en-us and there is no
  LocaleMiddleware.
- A build-time smoke import fails the build, not container start, on a
  broken venv.

arm64 image: 1,380 MB -> 889 MB. Covers and first pages of a CBR, CBZ and
PDF are byte-identical to the old image's. Both platforms build.

tests/test_dockerfile.py pins the apt list, the no-regex-names rule, the
venv-only copy and kept bytecode. .dockerignore now admits the Dockerfile
so the test runs in the CI image.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ajslater
ajslater merged commit 3b43595 into develop Oct 5, 2026
9 checks passed
@ajslater
ajslater deleted the docker-slim branch October 6, 2026 20:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant