From 45f98b269a16ef89878d14b21fcc71daa444b920 Mon Sep 17 00:00:00 2001 From: xiaoxia Date: Thu, 1 Oct 2026 19:42:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(deploy):=20#2129=20watchtower=20=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=83=A8=E7=BD=B2=E5=85=9C=E5=BA=95=E5=B9=82=E7=AD=89?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=20alembic=20=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因: watchtower 拉取新镜像后只 restart 容器,不会跑 deploy 脚本里的 `alembic upgrade head`;staging/prod 关闭了 AUTO_CREATE_SCHEMA, _ensure_viral_video_columns 不会执行,导致新列(copy_result/voice_id/ video_ratio/video_model)缺失,POST analyze-images 与 GET history 全部 500。 修复: - 新增 API 容器 entrypoint-api.sh:容器启动先幂等 alembic upgrade head, 失败仅告警不阻塞 uvicorn;支持显式 CMD 透传(CI 用 docker run/ compose run 传 sh -c '...' 时行为不变)。 - Worker 容器 entrypoint-worker.sh 同步加 alembic 步骤,避免 worker 先 于 API 启动时 Celery task 读新列报错。 - 修复 worker.Dockerfile 漏 COPY alembic/(只有 alembic.ini 没有 env.py/ versions,alembic 命令无法执行)。 - api.Dockerfile 用 ENTRYPOINT 替换原 CMD,entrypoint 内部 exec uvicorn。 tts/presets 401 由前端裸 fetch 未带 Bearer token 导致,已在 #2128 (5226680) 改为通过 apiClient 调用 voices/presets,一并随本次部署生效。 --- infra/docker/api.Dockerfile | 6 +++++- infra/docker/entrypoint-api.sh | 22 ++++++++++++++++++++++ infra/docker/entrypoint-worker.sh | 11 +++++++++++ infra/docker/worker.Dockerfile | 1 + 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100755 infra/docker/entrypoint-api.sh diff --git a/infra/docker/api.Dockerfile b/infra/docker/api.Dockerfile index db0cd8216..b41b786ec 100755 --- a/infra/docker/api.Dockerfile +++ b/infra/docker/api.Dockerfile @@ -30,6 +30,10 @@ COPY deploy/configs/douyin_cookies.txt /app/configs/douyin_cookies.txt # 强制升级 yt-dlp 到最新(抖音反爬经常变更,旧版 cookies 支持失效;#1968/#1963) RUN pip install --no-cache-dir -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com --upgrade "yt-dlp>=2026.8.19" +# API 启动入口(幂等迁移 + uvicorn)—— #2129: watchtower 自动部署兜底 +COPY infra/docker/entrypoint-api.sh /usr/local/bin/entrypoint-api.sh +RUN chmod +x /usr/local/bin/entrypoint-api.sh + # 设置环境变量 ENV PATH="/opt/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ENV PYTHONPATH=/app:/app/apps/api @@ -41,4 +45,4 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health', timeout=5)" # API 入口点 -CMD ["uvicorn", "apps.api.main:app", "--host", "0.0.0.0", "--port", "8000"] +ENTRYPOINT ["/usr/local/bin/entrypoint-api.sh"] diff --git a/infra/docker/entrypoint-api.sh b/infra/docker/entrypoint-api.sh new file mode 100755 index 000000000..c16bbc7ee --- /dev/null +++ b/infra/docker/entrypoint-api.sh @@ -0,0 +1,22 @@ +#!/bin/bash +# API 启动入口:先幂等执行数据库迁移,再启动传入的 CMD(默认 uvicorn) +# 解决 watchtower 自动拉取新镜像后容器重启、未跑 alembic upgrade head 导致新列缺失 500 的问题(#2129) +set -e + +cd /app + +echo "[entrypoint-api] Running alembic upgrade head..." +if alembic upgrade head; then + echo "[entrypoint-api] Migrations ok." +else + echo "[entrypoint-api] WARNING: alembic upgrade failed, continuing (existing columns should be fine)..." >&2 +fi + +# 若有显式 CMD(CI 部署时 docker compose run --rm api sh -c '...' 传入),直接 exec 它 +if [ "$#" -gt 0 ]; then + echo "[entrypoint-api] Exec custom command: $*" + exec "$@" +fi + +echo "[entrypoint-api] Starting uvicorn..." +exec uvicorn apps.api.main:app --host 0.0.0.0 --port 8000 diff --git a/infra/docker/entrypoint-worker.sh b/infra/docker/entrypoint-worker.sh index f9661149d..9d9bbd495 100755 --- a/infra/docker/entrypoint-worker.sh +++ b/infra/docker/entrypoint-worker.sh @@ -18,6 +18,17 @@ set -e +# #2129: 幂等执行数据库迁移(watchtower 自动部署兜底) +# worker 容器独立启动,不能依赖 API 容器先跑迁移 +cd /app +echo "[entrypoint-worker] Running alembic upgrade head..." +if alembic upgrade head; then + echo "[entrypoint-worker] Migrations ok." +else + echo "[entrypoint-worker] WARNING: alembic upgrade failed, continuing to start workers..." >&2 +fi +cd - >/dev/null + MAX_TASKS="${WORKER_MAX_TASKS_PER_CHILD:-100}" # ── 并发计算:显式 env 优先;否则从 WORKER_CONCURRENCY 按比例推导 ── diff --git a/infra/docker/worker.Dockerfile b/infra/docker/worker.Dockerfile index 6779c2304..10528ea7f 100755 --- a/infra/docker/worker.Dockerfile +++ b/infra/docker/worker.Dockerfile @@ -34,6 +34,7 @@ ENV APP_VERSION=$APP_VERSION # 复制文件(按变化频率从低到高排序,最大化层缓存命中) COPY alembic.ini /app/alembic.ini +COPY alembic/ /app/alembic/ COPY migrations/ /app/migrations/ COPY packages/ /app/packages/ # PR #1844 起,worker 还需要加载 apps.api.app.tasks.lipsync_tts,