onesvm-browser-server/stacks/browser-server.yml
chii 9b689b2476 feat: 落地节点指纹与 Cookie 罐,并按现网能力更新消费/接手文档
公开页抓取改为 Chrome 136 自洽身份 + 每节点 SQLite 养罐,Trafilatura 走 curl_cffi;MCP/README/接手说明与 09-02 现网复测对齐,避免消费方继续抄过期的站点三分表。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-02 17:04:25 +08:00

365 lines
No EOL
13 KiB
YAML
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.

# stacks/browser-server.yml — onesvm-browser-server Swarm stack(Contract §5-A5)。
#
# 权威对齐:docs/deploy-prod-preset-20260901.md §2 服务清单/镜像/资源/端口(逐字段);
# stack 必备字段对齐 onesvm-dev-md/base/deployment-rules.md §1.3
# (每服务 TZ / placement / restart_policy / resources.limits / healthcheck,backup 除外)。
# 测试期全钉 mgr1(placement node.hostname==swarm-mgr1);scheduler 因 SQLite 卷必须钉。
#
# 密钥注入面(deploy.env 提供,禁默认值禁入 git):
# BROWSER_SERVER_KEYS_SEED / BROWSER_SERVER_ADMIN_TOKEN / PROXY_SUB_URLS / SEARXNG_SECRET
# 部署:docker stack deploy -c stacks/browser-server.yml --resolve-image never browser-server
# 红线:本文件本轮仅交付,不执行部署(Contract §9)。
#
# O13 镜像 tag 约定:自研镜像 onesvm/browser-server:dev / onesvm/trafilatura-http:dev
# 日常迭代复用覆盖;第三方镜像 tag + digest 双锁(deployment-rules §2.3)。
version: "3.8"
x-restart: &restart
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 60s
x-placement-mgr1: &placement-mgr1
placement:
constraints:
- node.hostname==swarm-mgr1
services:
# ---------- 控制层(自研三角色,单二进制 role 分流) ----------
gateway:
image: onesvm/browser-server:dev
command: ["-role=gateway"]
environment:
TZ: Asia/Shanghai
BROWSER_SERVER_KEYS_SEED: ${BROWSER_SERVER_KEYS_SEED:?required}
BROWSER_SERVER_ADMIN_TOKEN: ${BROWSER_SERVER_ADMIN_TOKEN:?required}
BROWSER_SERVER_LISTEN_gateway: ":8640"
BROWSER_SERVER_SCHEDULER_URL: http://scheduler:8641
# gateway 与 scheduler 共库(gateway 只读 consumers/api_keys,写 audit/quota)。
BROWSER_SERVER_DB_PATH: /data/browser-server.db
volumes:
- browser-server-data:/data # 与 scheduler 共库(gateway 只读写 consumers/api_keys/audit/quota;
# SQLite 需目录可写以建 WAL 伴生文件,读写纪律由应用层单写者约定保证)
ports:
- "8640:8640" # host ingress(对外唯一入口;反代前缀 /bs-api)
networks:
# vlepontas-casa-net 附加(D10,对齐 WSG 先例);长格式显式声明 alias
# browser-server(V3 arch-review D-2:compose 校验器不接受列表内映射,
# 须用长格式;alias 防 vlepontas 消费方 DNS 解析失败)
browser-server-net:
aliases: []
casa-net:
aliases:
- browser-server
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1 # 测试期钉 mgr1(与共库卷同节点)
resources:
limits:
memory: 64m
cpus: "0.25"
healthcheck:
test: ["CMD", "/browser-server", "-healthz-probe"] # 见下方说明(distroless 无 curl/wget)
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
scheduler:
image: onesvm/browser-server:dev
command: ["-role=scheduler"]
environment:
TZ: Asia/Shanghai
BROWSER_SERVER_LISTEN_scheduler: ":8641"
BROWSER_SERVER_DB_PATH: /data/browser-server.db
BROWSER_SERVER_ADMIT_MAX: "60"
BROWSER_SERVER_WORKERS: "8"
BROWSER_SERVER_SEARXNG_CN_URL: http://searxng-cn:8080
BROWSER_SERVER_SEARXNG_GLOBAL_URL: http://searxng-global:8080
BROWSER_SERVER_TRAFILATURA_URL: http://trafilatura:8080
BROWSER_SERVER_LIGHTPANDA_CDP_HOST: lightpanda:9222
BROWSER_SERVER_SHELL_CDP_HOST: headless-shell:9222
BROWSER_SERVER_PROXYMANAGER_URL: http://proxymanager:8642
# MIHOMO 配置目录:proxymanager 写 provider 到挂载卷,mihomo 同卷读取。
BROWSER_SERVER_MIHOMO_CONFIG_DIR: /data/mihomo
MIHOMO_CONTROLLER_URL: http://mihomo:19090
volumes:
- browser-server-data:/data # named volume 钉 mgr1(SQLite 单写者,禁跨节点)
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 64m
cpus: "0.5"
healthcheck:
test: ["CMD", "/browser-server", "-role=scheduler", "-healthz-probe"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
proxymanager:
image: onesvm/browser-server:dev
command: ["-role=proxymanager"]
environment:
TZ: Asia/Shanghai
BROWSER_SERVER_LISTEN_proxymanager: ":8642"
PROXY_SUB_URLS: ${PROXY_SUB_URLS:?required}
# 订阅拉取专用 bootstrap(非密钥;缺省空=直连)。mgr1 直连机场被墙,
# 复用 mgr3 central-proxy :7890(deploy-preset §1)。探活仍走自家 mihomo。
BROWSER_SERVER_SUB_FETCH_PROXY: ${BROWSER_SERVER_SUB_FETCH_PROXY:-}
MIHOMO_CONTROLLER_URL: http://mihomo:19090
# provider 文件写到 mihomo 挂载卷(stack 把默认 /data/mihomo 指到 mihomo 同卷挂载点)。
BROWSER_SERVER_MIHOMO_CONFIG_DIR: /data/mihomo
# 热载路径必须是 mihomo 容器内视角(同卷挂 /root/.config/mihomo)。
BROWSER_SERVER_MIHOMO_RELOAD_PATH: /root/.config/mihomo/config.yaml
BROWSER_SERVER_DB_PATH: /data/browser-server.db
volumes:
- browser-server-data:/data # rules 表共享(gateway policy 联动)
- browser-server-mihomo:/data/mihomo # mihomo provider 写入点(与 mihomo 服务同卷)
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 32m
cpus: "0.1"
healthcheck:
test: ["CMD", "/browser-server", "-role=proxymanager", "-healthz-probe"]
interval: 30s
timeout: 3s
retries: 3
start_period: 10s
# ---------- 数据面 ----------
mihomo:
image: metacubex/mihomo:v1.19.24@sha256:9e37208fae8afa4c8b83d14ff2e9771b99178ebaf65a2c4fb388bc67ecefe4dc
volumes:
- browser-server-mihomo:/root/.config/mihomo # proxymanager 写 config.yaml/providers 到此(PM 侧 BROWSER_SERVER_MIHOMO_CONFIG_DIR=/data/mihomo 指同卷)
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
# 69 节点 + 订阅自带 dns/geosite 会加载 geoip(64m 实测 OOM 137)。
# 档标仍按 L2 超配;瘦 dns 后可回 64m(O12 校准)。
memory: 128m
healthcheck:
# mihomo controller 19090 REST 探活(仅 overlay;busybox sh 无 /dev/tcp,
# 用 busybox wget 打 /version——controller 无 secret 时返回 JSON)。
test: ["CMD-SHELL", "wget -q -O /dev/null http://127.0.0.1:19090/version || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
# ---------- Worker 层(第三方/自构建引擎,全部 pin) ----------
searxng-cn:
image: searxng/searxng:2026.8.29-d226b78bc@sha256:61ad36fcf71eb300f7d64216a6a04e010754755c7f5d33a526bd52e597e78c69
volumes:
- ./searxng-cn-settings.yml:/etc/searxng/settings.yml:ro
environment:
TZ: Asia/Shanghai
SEARXNG_BASE_URL: http://searxng-cn:8080/
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 192m
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
searxng-global:
image: searxng/searxng:2026.8.29-d226b78bc@sha256:61ad36fcf71eb300f7d64216a6a04e010754755c7f5d33a526bd52e597e78c69
volumes:
- ./searxng-global-settings.yml:/etc/searxng/settings.yml:ro
environment:
TZ: Asia/Shanghai
SEARXNG_BASE_URL: http://searxng-global:8080/
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 192m
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8080/healthz"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
trafilatura:
build:
context: ./trafilatura
image: onesvm/trafilatura-http:dev
environment:
TZ: Asia/Shanghai
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 192m
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request;urllib.request.urlopen('http://127.0.0.1:8080/health', timeout=3)"]
interval: 30s
timeout: 5s
retries: 3
start_period: 15s
lightpanda:
image: lightpanda/browser:0.3.7@sha256:447598e4c103b70b0fb610813e72795da44341c564e1ec872c3a490c1bc6aebe
command: ["/bin/lightpanda", "serve", "--host", "0.0.0.0", "--port", "9222", "--log_level", "info"]
environment:
TZ: Asia/Shanghai
# 境外出口统一走 mihomo(对齐 bench compose-lightpanda-proxy.yml 的 proxy env;
# 域名级直连/代理由 mihomo 规则裁决)。
HTTP_PROXY: http://mihomo:17890
HTTPS_PROXY: http://mihomo:17890
http_proxy: http://mihomo:17890
https_proxy: http://mihomo:17890
NO_PROXY: 127.0.0.1,localhost
no_proxy: 127.0.0.1,localhost
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 320m
# lightpanda 镜像内无 curl/wget/sh 工具链(distroless 风格),CDP 探活由
# scheduler 适配器 Health 上报承担(healthcheck 缺省即 deployment-rules 例外,注明)。
headless-shell:
image: chromedp/headless-shell:151.0.7922.109@sha256:5f877a2a559dea1a99fb750da695d28a020cdd49db660aead6c78a46e3c7dd50
command:
- --disable-dev-shm-usage
# 境外出口统一走 mihomo(对齐 bench compose:--proxy-server=http://mihomo:17890)。
- --proxy-server=http://mihomo:17890
# ENTRYPOINT /headless-shell/run.sh 已带 --no-sandbox、--remote-debugging-port=9223
# 与 socat 9222→9223 转发(bench compose 实测复用),不得覆盖端口。
shm_size: 128m
networks:
- browser-server-net
deploy:
replicas: 0 # 按需槽:平时 0,scheduler 经 Swarm API 拉起(空闲 10min 回收)
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 400m
healthcheck:
# headless-shell 基于 debian + socat(有 shell),探 CDP 调试端口。
test: ["CMD", "sh", "-c", "exec 3<>/dev/tcp/127.0.0.1/9222 || exit 1"]
interval: 30s
timeout: 5s
retries: 3
start_period: 10s
# ---------- 备份 sidecar(对齐组织 NAS sidecar 惯例) ----------
backup:
# 简化实现:每日 01:00(Asia/Shanghai)sqlite3 .backup → tar 到 /backup 卷。
# 说明:alpine 基础镜像无 sqlite3 包,这里用 busybox sleep 循环 + cp 快照
#(WAL 模式下 cp 非原子;严格一致性备份轮换 sqlite3/amd64 镜像后升级 .backup)。
image: alpine:3.20@sha256:c64c687cbea9300178b30c95835354e34c4e4febc4badfe27102879de0483b5e
command:
- /bin/sh
- -c
- |
# 每日 01:00 Asia/Shanghai 备份(TZ 已设 Asia/Shanghai):
# 1) sleep 到次日 01:00;2) cp 数据库(WAL 模式 + checkpoint 后主库自洽);
# 3) tar 打包进 /backup,保留最近 14 份。
while true; do
now=$$(date +%s); target=$$(date -d "tomorrow 01:00" +%s 2>/dev/null || echo $$((now + 86400)));
sleep $$((target - now));
ts=$$(date +%Y%m%d-%H%M%S);
cp /data/browser-server.db /data/browser-server.db-wal /tmp/ 2>/dev/null || true;
tar -czf /backup/browser-server-$$ts.tar.gz -C /data browser-server.db browser-server.db-wal browser-server.db-shm 2>/dev/null \
|| tar -czf /backup/browser-server-$$ts.tar.gz -C /data browser-server.db;
ls -1t /backup/browser-server-*.tar.gz | tail -n +15 | xargs -r rm -f;
done
environment:
TZ: Asia/Shanghai
volumes:
- browser-server-data:/data:ro
- browser-server-backup:/backup
networks:
- browser-server-net
deploy:
replicas: 1
<<: *restart
placement:
constraints:
- node.hostname==swarm-mgr1
resources:
limits:
memory: 32m
# 备份 sidecar 无对外服务,healthcheck 缺省(deployment-rules §1.3 例外,对齐 pg 备份 sidecar 惯例)。
# ---------- 网络 / 卷 ----------
networks:
browser-server-net:
driver: overlay
name: browser-server-net
casa-net:
external: true
name: vlepontas-casa-prod-net
volumes:
browser-server-data: {} # SQLite 库(scheduler 单写者;gateway 只读;钉 mgr1 由 placement 保证)
browser-server-mihomo: {} # mihomo 配置/provider(PM 写、mihomo 读)
browser-server-backup: {} # 备份产物(NAS 侧同步由部署轮另议)