feat: 部署改为 git 驱动,容器以宿主用户运行
服务器实测可经 Cloudflare 443 访问 Gitea 且 git 协议正常(此前我只测了 13000 端口就断言不可达,是错的),因此不再需要 tar + SFTP。 - docker-compose: 增加 user: "1000:1000"。容器此前以 root 运行,写进挂载目录的每轮 jsonl 产物都是 root 属主,导致宿主用户连自己的部署目录都挪不动 —— 这在把部署迁到 /mnt/data 时实际发生了 - deploy.sh: 一条命令走完 拉代码 →(webui/ 有改动时)重建前端 → 重启容器。前端产物 api/webui 是 gitignore 的,git pull 带不过来,必须在服务器上重建一次 - Dockerfile: 补 npm 包。corepack 只管 yarn/pnpm 不管 npm,而前端要在服务器上重建;这样服务器只需要 Docker,不必另配 Node 环境
This commit is contained in:
+4
-2
@@ -29,7 +29,9 @@ ENV PYTHONUNBUFFERED=1 \
|
||||
# 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.
|
||||
# (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.
|
||||
@@ -44,7 +46,7 @@ RUN set -eux; \
|
||||
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; \
|
||||
tzdata nodejs npm; \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# 更新这台机器上的部署。用法:
|
||||
#
|
||||
# ./deploy.sh
|
||||
#
|
||||
# 为什么需要脚本而不是一句 `git pull && docker compose up -d`:
|
||||
# 前端产物 api/webui 是 gitignore 的(它由 vite 生成),git pull 带不过来。
|
||||
# 所以代码更新之后必须在服务器上重建一次前端,否则页面还是旧的。
|
||||
# 这一步在容器里做,好处是服务器不需要装 Node —— 只有 Docker。
|
||||
#
|
||||
# node_modules 和 npm 缓存都留在挂载目录内,重复构建不会重新下载。
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
# 用镜像里的解释器跑,宿主机的 Python 版本无关。
|
||||
IMAGE=mediacrawler:latest
|
||||
|
||||
before=$(git rev-parse HEAD)
|
||||
git pull --ff-only
|
||||
after=$(git rev-parse HEAD)
|
||||
|
||||
if [ "$before" = "$after" ]; then
|
||||
echo "== 代码已是最新($after)"
|
||||
else
|
||||
echo "== 代码更新 $before -> $after"
|
||||
git --no-pager log --oneline "$before..$after" | sed 's/^/ /'
|
||||
fi
|
||||
|
||||
# 前端重建的两种情况:产物根本不存在(首次部署),或 webui/ 有改动。
|
||||
if [ ! -f api/webui/index.html ]; then
|
||||
need_build=1
|
||||
reason="前端产物不存在"
|
||||
elif [ "$before" != "$after" ] && ! git diff --quiet "$before" "$after" -- webui/; then
|
||||
need_build=1
|
||||
reason="webui/ 有改动"
|
||||
else
|
||||
need_build=0
|
||||
reason=""
|
||||
fi
|
||||
|
||||
if [ "$need_build" = "1" ]; then
|
||||
echo "== 重建前端($reason)"
|
||||
# -u 1000:1000 而不是 root:这里产出的文件要留在这个目录里给后面用,
|
||||
# 以 root 生成的 node_modules 会让下次构建和人工清理都变得别扭。
|
||||
# HOME 指向挂载目录,这样 npm 的缓存在宿主机上,重建时能复用。
|
||||
docker run --rm \
|
||||
-u 1000:1000 \
|
||||
-w /app/webui \
|
||||
-v "$PWD:/app" \
|
||||
-e HOME=/app/webui \
|
||||
-e npm_config_registry=https://registry.npmmirror.com \
|
||||
"$IMAGE" sh -c 'npm ci --no-audit --no-fund && npm run build'
|
||||
else
|
||||
echo "== 前端无改动,跳过构建"
|
||||
fi
|
||||
|
||||
echo "== 重启容器"
|
||||
docker compose up -d
|
||||
docker compose ps
|
||||
+10
-4
@@ -5,6 +5,13 @@ services:
|
||||
container_name: mediacrawler
|
||||
restart: unless-stopped
|
||||
|
||||
# Run as the user that owns this checkout. Without it the container is root,
|
||||
# and every file it writes into the mounted tree -- the crawler's per-run
|
||||
# jsonl output above all -- comes out root-owned. That does not break the app,
|
||||
# but it does lock the operator out of moving or deleting their own
|
||||
# deployment, which is exactly what happened the first time this was deployed.
|
||||
user: "1000:1000"
|
||||
|
||||
# host networking is a requirement, not a convenience: the crawler attaches
|
||||
# to the operator's Chrome at 127.0.0.1:9222, and inside a bridge network
|
||||
# that loopback is the container's own, where no browser is listening.
|
||||
@@ -20,8 +27,7 @@ services:
|
||||
|
||||
volumes:
|
||||
# The code is mounted rather than baked in, so shipping a change is
|
||||
# "re-upload the tarball, restart" instead of an image rebuild. Only the
|
||||
# dependencies live in the image, because those are the expensive part and
|
||||
# they change rarely -- rebuild only when requirements.txt or the
|
||||
# Dockerfile itself changes.
|
||||
# "git pull, restart" instead of an image rebuild. Only the dependencies
|
||||
# live in the image, because those are the expensive part and they change
|
||||
# rarely -- rebuild only when requirements.txt or the Dockerfile changes.
|
||||
- ./:/app
|
||||
|
||||
Reference in New Issue
Block a user