--- name: playwright-base-docker description: Use mcr.microsoft.com/playwright as a pre-baked Chrome base image for Dockerized crawler/automation projects source: auto-skill extracted_at: '2026-08-04T18:21:03.395Z' --- ## Problem Dockerizing headless Chrome automation requires Chromium, matching ChromeDriver, Xvfb, ffmpeg, and browser patching — which bloats the image and adds build steps. ## Approach Use `mcr.microsoft.com/playwright:-noble` (or similar variant) as the base image for worker/crawler services. Playwright ships with Chromium, ChromeDriver, and common browser automation dependencies pre-installed and pre-patched. ### Key steps 1. **Define multi-stage Dockerfile with separate targets** - `admin` target: lightweight `python:3.11-slim` (no Chrome needed for FastAPI) - `worker` target: `mcr.microsoft.com/playwright:v1.62.0-noble` (Chrome + deps included) 2. **Do NOT copy `.venv` from a different Python version builder stage** - The Playwright Noble image ships **Python 3.12** while `python:3.11-slim` ships 3.11. - Copying a 3.11-built venv into the image produces **broken shebangs** — `exec /app/.venv/bin/rq: no such file or directory` (the binaries exist but their `#!` line points to a non-existent Python 3.11). - **Fix**: install `uv` inside the worker stage and run `uv sync` natively so the venv targets the image's Python. 3. **Installing `uv` in the Playwright image** - Playwright ships Python but **not** `pip` or `uv` in PATH. - **Working approach**: ```dockerfile RUN python -m ensurepip --upgrade \ && python -m pip install --no-cache-dir --break-system-packages uv==0.11.31 \ && uv sync --frozen --no-dev --no-install-project ``` - `ensurepip` bootstraps pip in the same shell, then `python -m pip` installs the `uv` CLI into `/usr/local/bin/uv` (already in PATH). - Do **NOT** try to set `ENV PATH` in a separate layer before calling `uv` — the install script doesn't modify PATH, and the binary won't be found. - Avoid `curl -LsSf https://astral.sh/uv/install.sh | sh` in a RUN followed by `uv` in the next — the install script is a one-shot that doesn't persist PATH. 4. **Set environment variables** for Chrome location and headless mode: ```dockerfile ENV CHROME_BINARY=/usr/bin/chromium \ CHROMEDRIVER_PATH=/usr/bin/chromedriver \ HEADLESS=true ``` 5. **Skip `patch_driver.py`** — Playwright's Chromium is already pre-patched with undetected-chromedriver-friendly modifications. 6. **Update docker-compose.yml** with explicit build targets: ```yaml admin: build: context: . dockerfile: Dockerfile target: admin worker: build: context: . dockerfile: Dockerfile target: worker ``` ### Common pitfalls - **`//` in `FROM` lines doesn't work**: `FROM oci.reg.darano.ir//mcr.microsoft.com/playwright:latest AS worker` will fail with `invalid reference format`. The Docker parser confuses `//` with the `AS` syntax. If your registry requires `//` for internal routing, configure it at the **Docker daemon level** in `/etc/docker/daemon.json` under `registry-mirrors`, not in the Dockerfile. - **Don't copy venv from python:3.11-slim to Playwright**: Python version mismatch → broken shebangs. Always build the venv natively in the target stage. - **Don't rely on `pip` being available**: Playwright ships Python without pip. Use `python -m ensurepip` first. ## What you still need - **ffmpeg** and **Xvfb**: The Playwright image includes these for session recording. If you need them for headless mode only (no recording), they are optional. - **security_opt**: Workers still need `cap_add: [SYS_ADMIN]` and `security_opt: [seccomp:unconfined]` for undetected-chromedriver to fully spoof browser fingerprints. - **shm_size**: Keep `shm_size: "2gb"` on worker containers to prevent Chrome OOM crashes. ## Files changed - `Dockerfile` — split into `admin` and `worker` targets - `docker-compose.yml` — explicit `target` per service, separate image names ## Why this matters - **Faster builds** — no Chromium download, no ChromeDriver version matching, no patching script - **Smaller admin image** — admin panel doesn't need any browser dependencies - **Reliable driver matching** — Playwright maintains its own bundled Chromium/ChromeDriver pair, eliminating version mismatches