Skip to content

perf: shrink app image and speed Docker CI/CD - #22

Merged
maryammouzarani2024 merged 8 commits into
OWASP:mainfrom
rgbuilds:docker-ci-optimizations
Aug 27, 2026
Merged

maryammouzarani2024 merged 8 commits into
OWASP:mainfrom
rgbuilds:docker-ci-optimizations

Conversation

@rgbuilds

@rgbuilds rgbuilds commented Aug 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • App image starts Flask only. Ollama stays the separate Compose service (ollama/ollama:latest); unused Dockerfile.ollama is removed.
  • Install CPU PyTorch from the PyTorch CPU index before requirements.txt so sentence-transformers does not pull the CUDA wheel. requirements.txt stays unpinned so host/macOS venvs are unchanged.
  • Drop pip's download cache, apt recommended packages, and build-essential (wheels cover the Python deps). Keep libzbar0 for QR labs.
  • .dockerignore keeps tests/docs/CI out of the published image; make test-docker bind-mounts tests.
  • CI: Buildx + GitHub Actions cache for GHCR pushes; pytest runs once via test.yml (3.12 + test extras); docs-only changes skip test/lint/image jobs; lint Actions match test (checkout@v4, setup-python@v5).

Lab Python is unchanged.

Image size (linux/arm64 local build)

docker images docker inspect .Size
Published ghcr.io/owasp/pwnzzai:latest 15.3 GB 6.11 GB
This branch 2.04 GB 441 MB

Installed torch is CPU-only (2.13.0+cpu on this machine; unpinned). MiniLM encode still returns (1, 384).

Test plan

  • make test-docker (pytest in the rebuilt image): 202 passed, 65 skipped
  • Image CMD is Flask only; no ollama / gcc / tests/ in the image
  • Workflow YAML and both Compose files parse; ci-docker.yml calls test.yml then Buildx push
  • Local sanity: /, /basics, /login, Ollama status, QR decode, RAG query, docker-smoke-test.sh Option 1 + 2
  • GitHub Actions on this PR: lint + test
  • After merge: GHCR latest pull on linux/amd64 and docker compose up (/ and /check-ollama-status)

CMD started `ollama serve` inside the Flask image, but that image never shipped an Ollama binary. Compose already runs `ollama/ollama:latest` as a second service, and the leftover command failed or no-oped at startup. Dockerfile.ollama was a wrapper Compose never referenced.
pip keeps wheels under /root/.cache/pip in the same layer (~3 GB here). apt's recommended packages are not needed at runtime. --no-cache-dir and --no-install-recommends keep those files out of what we publish.
sentence-transformers depends on torch. The default PyPI wheel is CUDA plus nvidia-* packages, even though RAG labs only embed on CPU (MiniLM, 384-d). Installing the CPU index first stops the CUDA stack from landing in the image. requirements.txt stays unpinned so host/macOS venvs are unchanged.
Current Python deps install from wheels, so gcc was only adding ~300 MB to the final image. libzbar0 stays: it is the runtime library for pyzbar (QR labs). No multi-stage build; the compiler is simply not installed.
COPY . . was shipping tests/, docs/, deploy/, scripts/, and .github/ into the published image. .dockerignore excludes them. make test-docker bind-mounts tests/ so image pytest still runs without baking that tree in.
Hosted runners start empty, so every GHCR push rebuilt every layer from scratch. Buildx plus type=gha reuses layers across runs. Tags stay ghcr.io/owasp/pwnzzai:latest and the full git sha.
ci-docker.yml ran a second pytest (3.11, weaker install) on every push, while test.yml already runs the full suite (3.12 + requirements-test.txt). Reuse that workflow, cache pip, cancel overlapping runs, and ignore docs/** / *.md so documentation PRs do not rebuild or push images.
lint still used older checkout/setup-python while test and docker jobs did not. Bump to checkout@v4 and setup-python@v5, and apply the same docs-only paths-ignore and concurrency so lint does not run twice or on markdown-only changes.
@rgbuilds

Copy link
Copy Markdown
Contributor Author

Local sanity (linux/arm64, image pwnzzai-local:pr-head)

Manual UI was on host port 8081 (local compose only). Smoke script used 8080.

  • GET /, /basics, /login → 200
  • /check-ollama-status → 200; UI: “Ollama is running with 1 models available”
  • Direct prompt injection, Free Model (llama3.2:1b) → chat 200
  • QR lab: decode http://en.m.wikipedia.org (POST /upload-qr 200) — libzbar0 still present
  • RAG lab: upload/index + query 200 — CPU embeddings still work
  • APP_IMAGE=pwnzzai-local:pr-head ./scripts/docker-smoke-test.sh — Option 1 and Option 2 passed

App logs are Flask only (no ollama serve / ollama: not found). Lab behavior unchanged.

Screenshots in time order below.

Screenshot 2026-08-25 at 11 57 21 PM Screenshot 2026-08-25 at 11 57 47 PM Screenshot 2026-08-25 at 11 58 02 PM Screenshot 2026-08-25 at 11 58 44 PM Screenshot 2026-08-25 at 11 59 17 PM Screenshot 2026-08-26 at 12 01 34 AM Screenshot 2026-08-26 at 12 01 40 AM Screenshot 2026-08-26 at 12 07 01 AM Screenshot 2026-08-26 at 12 07 10 AM Screenshot 2026-08-26 at 12 11 06 AM Screenshot 2026-08-26 at 12 11 15 AM Screenshot 2026-08-26 at 12 11 23 AM Screenshot 2026-08-26 at 12 15 24 AM

@maryammouzarani2024 maryammouzarani2024 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not a good idea to hardcode the library version.

@rgbuilds
rgbuilds force-pushed the docker-ci-optimizations branch from dc7a247 to 7e7c95b Compare August 27, 2026 06:54
@rgbuilds

Copy link
Copy Markdown
Contributor Author

It is not a good idea to hardcode the library version.

@maryammouzarani2024 Thanks for the feedback. I have removed the commit which hardcoded the version and updated the same PR.

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.

2 participants