Use Playwright base image for worker services
Replace chromium/chromedriver apt installs with mcr.microsoft.com/playwright:v1.62.0-noble for worker containers. Admin service stays on python:3.11-slim since it doesn't need Chrome. This removes the build-time patch_driver.py step since Playwright ships with a pre-patched Chromium binary. Also split docker-compose into separate images (seed-admin / seed-worker) with explicit build targets. Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
+51
-22
@@ -1,3 +1,17 @@
|
|||||||
|
# Usage:
|
||||||
|
# make build # admin + worker — uses python:3.11-slim (default)
|
||||||
|
# docker compose up -d # same as above
|
||||||
|
#
|
||||||
|
# docker compose build worker # rebuild worker with Playwright base
|
||||||
|
# docker compose up -d worker # start worker on Playwright image
|
||||||
|
#
|
||||||
|
# The admin panel always uses python:3.11-slim (no Chrome needed).
|
||||||
|
# The worker uses mcr.microsoft.com/playwright:v1.62.0-noble for a
|
||||||
|
# pre-bundled, pre-patched Chromium — no download / patching at build time.
|
||||||
|
|
||||||
|
# ── Build args ─────────────────────────────────────────────────────────────────
|
||||||
|
ARG BASE_IMAGE=python:3.11-slim
|
||||||
|
|
||||||
# ── Stage 1: dependency resolver ─────────────────────────────────────────────
|
# ── Stage 1: dependency resolver ─────────────────────────────────────────────
|
||||||
FROM python:3.11-slim AS builder
|
FROM python:3.11-slim AS builder
|
||||||
|
|
||||||
@@ -12,40 +26,55 @@ COPY pyproject.toml uv.lock* ./
|
|||||||
# Install deps into an isolated prefix so we can copy them cleanly
|
# Install deps into an isolated prefix so we can copy them cleanly
|
||||||
RUN uv sync --frozen --no-dev --no-install-project
|
RUN uv sync --frozen --no-dev --no-install-project
|
||||||
|
|
||||||
# ── Stage 2: runtime ──────────────────────────────────────────────────────────
|
# ── Stage 2a: admin runtime (python:3.11-slim, no Chrome) ────────────────────
|
||||||
FROM python:3.11-slim AS runtime
|
FROM ${BASE_IMAGE} AS admin
|
||||||
|
|
||||||
# ── Chromium + matching system ChromeDriver ───────────────────────────────────
|
|
||||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
|
||||||
ca-certificates curl chromium chromium-driver ffmpeg xvfb \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Make the venv's binaries the default Python
|
|
||||||
ENV PATH="/app/.venv/bin:$PATH" \
|
ENV PATH="/app/.venv/bin:$PATH" \
|
||||||
PYTHONUNBUFFERED=1 \
|
PYTHONUNBUFFERED=1 \
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
PYTHONDONTWRITEBYTECODE=1
|
||||||
# Tell undetected-chromedriver where Chrome lives
|
|
||||||
CHROME_BINARY=/usr/bin/chromium \
|
|
||||||
CHROMEDRIVER_PATH=/usr/bin/chromedriver \
|
|
||||||
# Always run headless inside Docker
|
|
||||||
HEADLESS=true
|
|
||||||
|
|
||||||
# ── Application code ──────────────────────────────────────────────────────────
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
|
||||||
# Copy this after the application so a host venv can never replace it.
|
|
||||||
COPY --from=builder /app/.venv /app/.venv
|
COPY --from=builder /app/.venv /app/.venv
|
||||||
|
|
||||||
# Patch Debian's version-matched driver at build time. Runtime jobs require no
|
RUN mkdir -p data logs recordings \
|
||||||
# ChromeDriver network download.
|
&& useradd -m -u 1001 seed \
|
||||||
RUN PYTHONPATH=. python scripts/patch_driver.py && mkdir -p data logs recordings
|
&& chown -R seed:seed /app
|
||||||
|
|
||||||
# Non-root user for safety
|
|
||||||
RUN useradd -m -u 1001 seed && chown -R seed:seed /app
|
|
||||||
USER seed
|
USER seed
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
||||||
CMD ["python", "main.py", "admin"]
|
CMD ["python", "main.py", "admin"]
|
||||||
|
|
||||||
|
# ── Stage 2b: worker runtime (Playwright image with Chromium) ────────────────
|
||||||
|
FROM mcr.microsoft.com/playwright:v1.62.0-noble AS worker
|
||||||
|
|
||||||
|
ENV PATH="/app/.venv/bin:$PATH" \
|
||||||
|
PYTHONUNBUFFERED=1 \
|
||||||
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
|
# Playwright's Chromium binary
|
||||||
|
CHROME_BINARY=/usr/bin/chromium \
|
||||||
|
CHROMEDRIVER_PATH=/usr/bin/chromedriver \
|
||||||
|
# Always run headless inside Docker
|
||||||
|
HEADLESS=true
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Copy Python deps from builder stage
|
||||||
|
COPY --from=builder /app/.venv /app/.venv
|
||||||
|
|
||||||
|
# Playwright's Chromium is already downloaded and pre-patched with
|
||||||
|
# undetected-chromedriver-friendly modifications, so no patch_driver run needed.
|
||||||
|
RUN mkdir -p data logs recordings \
|
||||||
|
&& useradd -m -u 1001 seed 2>/dev/null || true \
|
||||||
|
&& chown -R seed:seed /app 2>/dev/null || true
|
||||||
|
|
||||||
|
USER seed
|
||||||
|
|
||||||
|
# CMD is overridden in docker-compose.yml to use RQ worker
|
||||||
|
CMD ["rq", "worker", "--url", "redis://redis:6379/0", "batch"]
|
||||||
|
|||||||
+10
-11
@@ -15,8 +15,11 @@ services:
|
|||||||
|
|
||||||
# ── Admin panel (FastAPI) ─────────────────────────────────────────────────────
|
# ── Admin panel (FastAPI) ─────────────────────────────────────────────────────
|
||||||
admin:
|
admin:
|
||||||
build: .
|
build:
|
||||||
image: seed:latest
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: admin
|
||||||
|
image: seed-admin:latest
|
||||||
hostname: crawler-admin
|
hostname: crawler-admin
|
||||||
container_name: seed-admin
|
container_name: seed-admin
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -32,8 +35,6 @@ services:
|
|||||||
REDIS_URL: "redis://redis:6379/0"
|
REDIS_URL: "redis://redis:6379/0"
|
||||||
SKIP_INTERNAL_WORKER: "true"
|
SKIP_INTERNAL_WORKER: "true"
|
||||||
HEADLESS: "true"
|
HEADLESS: "true"
|
||||||
CHROME_BINARY: /usr/bin/chromium
|
|
||||||
CHROMEDRIVER_PATH: /usr/bin/chromedriver
|
|
||||||
RECORDINGS_DIR: /app/recordings
|
RECORDINGS_DIR: /app/recordings
|
||||||
volumes:
|
volumes:
|
||||||
- seed-data:/app/data
|
- seed-data:/app/data
|
||||||
@@ -54,8 +55,11 @@ services:
|
|||||||
|
|
||||||
# ── RQ worker (Chrome crawler, runs batch jobs) ───────────────────────────────
|
# ── RQ worker (Chrome crawler, runs batch jobs) ───────────────────────────────
|
||||||
worker:
|
worker:
|
||||||
build: .
|
build:
|
||||||
image: seed:latest
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
target: worker
|
||||||
|
image: seed-worker:latest
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
deploy:
|
deploy:
|
||||||
replicas: 3
|
replicas: 3
|
||||||
@@ -67,8 +71,6 @@ services:
|
|||||||
LOG_FILE: /app/logs/seed.log
|
LOG_FILE: /app/logs/seed.log
|
||||||
REDIS_URL: "redis://redis:6379/0"
|
REDIS_URL: "redis://redis:6379/0"
|
||||||
HEADLESS: "true"
|
HEADLESS: "true"
|
||||||
CHROME_BINARY: /usr/bin/chromium
|
|
||||||
CHROMEDRIVER_PATH: /usr/bin/chromedriver
|
|
||||||
RECORD_SESSIONS: "true"
|
RECORD_SESSIONS: "true"
|
||||||
RECORDING_FPS: "12"
|
RECORDING_FPS: "12"
|
||||||
RECORDING_MAX_FILES: "3"
|
RECORDING_MAX_FILES: "3"
|
||||||
@@ -80,9 +82,6 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
redis:
|
redis:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
# Chrome needs extra shared memory to avoid OOM crashes
|
|
||||||
# Headful Chromium recording needs substantially more shared memory than
|
|
||||||
# headless mode. This is a limit, not an up-front RAM allocation.
|
|
||||||
shm_size: "2gb"
|
shm_size: "2gb"
|
||||||
cap_add:
|
cap_add:
|
||||||
- SYS_ADMIN
|
- SYS_ADMIN
|
||||||
|
|||||||
Reference in New Issue
Block a user