Files
splitsec2andMichael Ngo fcdc2dfb69 perf(docker): stop shipping build-only content in the runtime image (#1404)
While checking why each build took so much disk on my server, I looked
at what's actually in the runtime image. A good share of it is there for
the build and never used after.

**The C toolchain.** The base stage installs `gcc`, `g++`, `libffi-dev`
and `python3-dev` for building C extensions, and they stay in both the
full and lite images, which is 290 MB installed. Nothing gets compiled
any more. Every compiled dependency in `uv.lock` (cffi, gevent,
greenlet, zope-interface) ships a cp314 manylinux wheel for both amd64
and arm64, and the packages that only have an sdist are pure Python.
`python3-dev` was also pulling Debian's `libpython3.13` into a 3.14
image.

**The build context.** `COPY . .` puts the whole context into `/app`, so
`tests/`, `docs/` and the frontend source ship too. `.dockerignore` now
leaves out the trees nothing reads at runtime. `src/` can't go in
`.dockerignore` because the frontend-builder stage needs it, so both
final stages remove it after the built dist is copied. The venv's own
`pip` goes as well, since uv seeds one and nothing installs at runtime.
This part is @DrNgo's work from his fork, and the commit carries his
name.

Measured by building both targets on native amd64 and arm64 runners:

|  | amd64 full | amd64 lite | arm64 full | arm64 lite |
|---|---|---|---|---|
| before | 1,532 MB | 589 MB | 1,528 MB | 619 MB |
| after | 1,238 MB | 295 MB | 1,251 MB | 342 MB |

Compressed, the full image goes from 617 MB to 504 MB on amd64.

On both architectures the image builds, reaches healthy, and Chromium
starts the same way the bypasser starts it (xvfb,
`_get_browser_args()`). The Python suite passes too. It's also running
on my own install now.

If a dependency ever needs compiling again, the clean fix is a builder
stage that builds the wheel and copies it in, rather than putting the
toolchain back in the runtime image. Happy to add that now if you'd
rather have it in place.

---------

Co-authored-by: Michael Ngo <michaeln56@gmail.com>
2026-10-02 16:30:10 -04:00

70 lines
1.2 KiB
Plaintext

.git
.github
.vscode
.local
.mypy_cache
README_images
.gitignore
Dockerfile
.dockerignore
.DS_Store
docker-compose.yml
docker-compose.*.yml
readme.md
# Python specific
__pycache__/
*.pyc
*.pyo
*.pyd
# Environment files
.env*
# Test & Coverage artifacts
.pytest_cache/
.coverage
htmlcov/
# Logs
*.log
# Build artifacts
build/
dist/
*.egg-info/
# Virtual environments
venv/
.venv/
env/
# Frontend build artifacts (built in separate stage)
src/frontend/node_modules/
src/frontend/dist/
src/frontend/.vite/
# Old frontend code (replaced by src/frontend)
templates/
static/css/
static/js/
# Developer-only trees. `COPY . .` puts the whole context into /app, so anything
# left here ships to production: the CodeGraph index alone was 38MB of the image.
# NOTE: this file applies to EVERY stage, so `src/` cannot be listed — the
# frontend-builder stage needs it. The final stage drops it after the copy.
# Deliberately NOT listed: `data/` (languages.py:19 reads
# data/book-languages.json at runtime) and `genDebug.sh` (the final stage
# chmod +x's it, so excluding it fails the build).
.codegraph/
.ruff_cache/
.claude/
tests/
docs/
scripts/
compose/
downloaded_files/
frontend-dist/
SESSION_STATE.md
Makefile