# Backend image: FastAPI + APScheduler + Alembic + scrapers. # # Keeps the image small (python:3.12-slim) and the layer cache hot by copying # only pyproject.toml first and installing deps before the source lands. The # same image serves both the API (uvicorn) and the scheduler # (``python -m app.sync.cli scheduler``) — the docker-compose ``command:`` key # selects which entrypoint runs. FROM python:3.12-slim # Build-time / runtime deps for asyncmy (compiled C extension) + httpx + # cryptography.``libmariadb`` is what asyncmy links against on Debian. # Playwright 系统依赖:Chromium headless 需要的共享库(libnss3/libatk/libx11 # 等,playwright install-deps 的等价精简集,2026-08-21 部署阻塞点#1)。 # 国内构建加速(阿里云 ECS 上 apt/pip 直连官方源慢或超时;对本地构建同样 # 可用,镜像源无地域限制)。bookworm/trixie 的源都在 debian.sources 里; # 文件不存在(更老基础镜像)则跳过,不影响构建。 RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources 2>/dev/null || true RUN apt-get update \ && apt-get install -y --no-install-recommends \ build-essential \ libmariadb-dev \ libffi-dev \ # Chromium headless 依赖(playwright 官方 install-deps 清单) libnss3 \ libnspr4 \ libatk1.0-0 \ libatk-bridge2.0-0 \ libcups2 \ libdrm2 \ libxkbcommon0 \ libxcomposite1 \ libxdamage1 \ libxfixes3 \ libxrandr2 \ libgbm1 \ libasound2 \ libpango-1.0-0 \ libcairo2 \ libatspi2.0-0 \ libx11-6 \ libxcb1 \ libxext6 \ libexpat1 \ && rm -rf /var/lib/apt/lists/* WORKDIR /app # Install dependencies first (cache-friendly: only re-installs when # pyproject.toml changes). The project itself is installed in editable-like # mode by copying the package in afterwards. COPY pyproject.toml ./ COPY app/__init__.py app/__init__.py COPY app/ ./app/ # scripts/ — 调度器的页面抓取入口(scripts/scrape_via_page.py 与 # full_sync_all.sh 由 scheduler._page_subprocess 以 cwd=/app 调起, # 2026-08-21 部署阻塞点#2:镜像里必须带上)。 COPY scripts/ ./scripts/ # alembic.ini + migrations/ — 容器内可跑 `alembic upgrade head`(DB_URL # 环境变量已由 compose 注入;entrypoint 不自动迁移,由运维手动执行, # 见 docs/DEPLOY.md「数据库迁移」)。alembic.ini 的 script_location 用 # %(here)s 相对 ini 自身,落在 /app/migrations 正好对上。 COPY alembic.ini ./ COPY migrations/ ./migrations/ # Install the package + dev dependencies (the dev extras include aiosqlite + # pytest, which are tiny and convenient for in-container smoke checks). Pin # the install to the local source so the package import path resolves. # 国内构建加速:pip 走阿里云源;Chromium 二进制(~160MB)走 npmmirror, # 否则 ECS 上从 playwright CDN 下载很慢。 ENV PLAYWRIGHT_DOWNLOAD_HOST=https://cdn.npmmirror.com/binaries/playwright RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ -e ".[dev]" \ && playwright install chromium --with-deps # Default command — overridden per-service in docker-compose. The API service # runs uvicorn; the scheduler service runs the CLI. CMD ["uvicorn", "app.api.main:app", "--host", "0.0.0.0", "--port", "8000"]