# Server deployment image. # # No browser is bundled on purpose. On this deployment the crawler attaches over # CDP to the Chrome already running on the host (see the 接管已有 Chrome setting), # so shipping a second copy of Chromium would only add hundreds of megabytes and # a login state that nothing uses. The Playwright Python package is still needed # -- that is what speaks CDP -- hence PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD. FROM python:3.11-slim ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ PIP_DISABLE_PIP_VERSION_CHECK=1 \ PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \ TZ=Asia/Shanghai # asyncmy compiles a Cython extension, so a toolchain has to exist at build time. # It is left installed: purging it risks taking libmysqlclient with it, and a # slightly larger image is cheaper than a runtime that fails months later. # # deb.debian.org is effectively unusable from this network -- it was pulling the # 96 MB of build dependencies at roughly 13 kB/s, which puts a build at well over # half an hour. Point apt at a domestic mirror; override APT_MIRROR when building # from somewhere that does not need it. # # The libgl1/libxcb1/... group is not for a GUI: opencv-python links against X11 # at import time, and tools/utils.py reaches cv2 through slider_util, so without # them the *application* fails to import, not just some image utility. tzdata is # here because TZ=Asia/Shanghai is silently ignored without it, which would put # every stored timestamp in UTC. nodejs is for PyExecJS: douyin/help.py compiles # libs/douyin.js at *import* time, and because main.py imports every platform, # that single platform being importable-or-not decides whether the whole app # (and the environment self-check) comes up. npm rides along so the WebUI can be # rebuilt on the server (see deploy.sh) instead of only on a workstation -- # corepack is present but does not cover npm, only yarn and pnpm. # # The pip mirror is set for the same reason as the apt one: this host's route to # the public index is slow. ARG APT_MIRROR=mirrors.tuna.tsinghua.edu.cn RUN set -eux; \ for f in /etc/apt/sources.list /etc/apt/sources.list.d/debian.sources; do \ if [ -f "$f" ]; then \ sed -i "s|deb.debian.org|${APT_MIRROR}|g; s|security.debian.org|${APT_MIRROR}|g" "$f"; \ fi; \ done; \ apt-get update; \ apt-get install -y --no-install-recommends \ build-essential pkg-config default-libmysqlclient-dev \ libgl1 libglib2.0-0 libsm6 libxext6 libxrender1 libxcb1 libgomp1 \ tzdata nodejs npm; \ rm -rf /var/lib/apt/lists/* WORKDIR /app # Requirements only -- this is the one layer that is expensive to build and # changes rarely. ARG PIP_INDEX=https://pypi.tuna.tsinghua.edu.cn/simple COPY requirements.txt ./ RUN pip install --no-cache-dir -i "$PIP_INDEX" -r requirements.txt # The application code is deliberately NOT copied in. compose mounts it at /app, # so a code change is "re-upload the tarball, restart the container" instead of # an image rebuild. Treat this image as the dependency layer and nothing else; # rebuild it when, and only when, requirements.txt or this file changes. EXPOSE 18051 # api.main reads MC_HOST / MC_PORT from the environment; compose supplies both. CMD ["python", "-m", "api.main"]