Files
csctalon/backend/Dockerfile
tanzk a984cb99e3 fix(deploy): 消除 Gunicorn -w 4/-w 1 矛盾,部署三处统一单 worker (#212)
Dockerfile.patch(应急补丁镜像,FROM csctalon-backend:latest 仅覆盖代码)
内嵌 CMD 为 -w 4,与主 Dockerfile / docker-compose.yml 的 -w 1 冲突。
核实部署路径:compose `build: ./backend` 且用 command 显式覆盖为 -w 1,
patch 不被 compose 引用;但 patch 被直接 `docker run` 时其内嵌 CMD 生效,
会破坏单 worker 前提(R-P1-9)。

- Dockerfile.patch: -w 4 → -w 1;
- Dockerfile / docker-compose.yml / Dockerfile.patch 三处补注释,写明单 worker
  与进程内状态的关系:llm_scheduler 的进程级 threading.Condition 门闸(_gates,
  任一时刻仅 1 个 LLM 调用,多 worker 会并发打爆单 ollama 端点)、
  SyncTaskManager 同步互斥、core.rate_limit 登录限速进程内计数;多 worker
  水平扩容须先迁 Redis,v0.7 明确「立此存照、不做」;
- 顺手纠正 app/core/rate_limit.py 陈旧「Dockerfile -w 4」注释。

验证:全仓 grep 三个真实启动点唯一 -w 1(其余为说明性注释/第三方 reference/);
docker-compose.yml YAML 合法(backend command -w=1);ruff 全绿。
回填台账 R-P1-9。
2026-10-07 20:36:28 +08:00

59 lines
3.1 KiB
Docker
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 客服中心管理系统 后端镜像
FROM python:3.11-slim
WORKDIR /app
# 替换 apt 为清华源(加速国内下载)
RUN sed -i 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g; s|security.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list.d/debian.sources 2>/dev/null \
|| sed -i 's|deb.debian.org|mirrors.tuna.tsinghua.edu.cn|g; s|security.debian.org|mirrors.tuna.tsinghua.edu.cn|g' /etc/apt/sources.list 2>/dev/null \
|| true
# 系统依赖(libpq 编译所需 + libzbar 用于发票二维码解码)
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc libpq-dev \
# 发票二维码本地解码(规划设计 §4.5, pyzbar 依赖)
libzbar0 \
# Playwright/Chromium 依赖
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
libgbm1 libasound2 libpangocairo-1.0-0 libpango-1.0-0 libcairo2 \
# 虚拟显示服务(工单 #45): 共享文档页面内扫码登录需在有头浏览器中渲染,
# 容器无物理显示器 → 用 Xvfb 提供虚拟 DISPLAY。xauth 供 xvfb-run 使用。
xvfb xauth \
&& rm -rf /var/lib/apt/lists/*
# pip 使用清华源
RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple \
&& pip config set global.trusted-host pypi.tuna.tsinghua.edu.cn
COPY pyproject.toml ./
COPY app ./app
# 依赖单一来源 = pyproject.toml (#183): 安装本项目即解析全部依赖,
# 杜绝 Dockerfile 硬编码清单与 pyproject 双定义漂移。
RUN pip install --no-cache-dir .
# 安装 Chromium 浏览器(浏览器二进制走 npmmirror 镜像,避免 cdn.playwright.dev 国内无法访问)
ENV PLAYWRIGHT_DOWNLOAD_HOST=https://npmmirror.com/mirrors/playwright/
RUN playwright install chromium --with-deps
COPY . /app
# 上传目录(bind mount 到宿主机 ./backend/uploads)
RUN mkdir -p /app/uploads
EXPOSE 8000
# gunicorn + uvicorn worker
# -w 1: 单 worker, 与 docker-compose.yml、Dockerfile.patch 三处保持一致(#212 已消除 -w 4 矛盾)。
# 原因(下列状态均为进程内状态,多 worker 各持一份即失效):
# · llm_scheduler 的进程级 threading.Condition 门闸(_gates): 保证任一时刻仅 1 个 LLM
# 调用在飞,多 worker 会把单个 ollama 端点并发打爆;
# · 同步任务管理器(SyncTaskManager) / 登录限速(core.rate_limit) 的内存锁与计数:
# 多 worker 各自计数会导致重复同步(数据重复)与限速失效。
# 多 worker 水平扩容是 v0.7「立此存照、不做」项;如需,须先将这些状态迁至 Redis。
# --timeout 900s: sync-all 多源抓取含 65s 间隔, 全程 5-8 分钟, 默认 120s 会被 gunicorn
# 判超时 SIGABRT → 前端 502。
# 日志: gunicorn/uvicorn/app 日志统一走 stdout/stderr, 由 docker json-file 轮转(10m×3)捕获,
# 用 `docker compose logs backend` 查看; nginx 访问日志另以文件形式落在 ./logs/nginx。
CMD ["gunicorn", "app.main:app", "-w", "1", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000", "--timeout", "900", "--log-level", "info"]