发 v1.0.9 前发现两个真问题,都会直接影响用户拿到的附件。 一、docker-compose.yml 里的镜像标签是硬编码的 1.0.8 这两个文件是**直接挂到 GitHub Release 上的附件**,用户照着抄命令。 早先它们硬编码具体版本号,每次发版要人工 sed 一遍 —— 这次就漏了: 附件里写着 `image: drouter:1.0.8`,而镜像 tar 加载后的标签是 `drouter:1.0.9`, `docker compose up` 直接报「找不到镜像」。DOCKER-GUIDE.md 另有 14 处同样问题。 改成 __VERSION__ 模板,由 build-docker.sh 渲染(版本从 packaging/VERSION 读)。 渲染分两步,顺序不能反:先删 TEMPLATE-NOTE 标记块(那是给维护者看的 「这是模板」提示,留着用户会看到「1.0.9 是占位符」这种自相矛盾的话), 再替换占位符。先替换的话,标记块里的 __VERSION__ 也会被换掉。 retag-docker-image.py 同样问题:NEW_TAGS 硬编码。改完参数化。 这个 bug 更隐蔽 —— 拿 1.0.9 的镜像跑重标记会打上 1.0.8 的标签, 用户 load 完看到的标签与附件说明对不上。 t-packaging.py 补 12 条判据卡住这些(4 条已做反向验证:注入即红、还原即绿)。 判据只抓「紧挨 drouter 标识或产物文件名」的版本号 —— 一刀切拦所有 x.y 会 误伤「1.0.1 起 Web 终端绕开 init」这种历史沿革说明和「GPL-3.0」许可证名。 二、t-worktree-clean.py 抓不到「注释掉整行代码」型注入 跑回归时 t-107 红了 1 项,查出来是 t-107-inject-wg.py 把 `'env': _vpn_env(),` 注释掉了没还原(SIGTERM 打断,finally 没执行)—— 和 v1.0.8 那次 `/nonexistent` 残留一模一样的坑,但**形态不同**: 不含任何哨兵字样,原判据的 4 个哨兵全都抓不到。 后果很实:_vpn_status 不返回 env,前端拿不到四态诊断, VPN 页面的三个修复按钮全废。这正是 v1.0.8 声称修好的那个 bug。 补两条判据: - 扫「被注释掉的整行代码」:去掉 # 后能 ast.parse 成功,且含调用/赋值/return/dict 项 - 扫 CRLF:Windows 工具写文件会整篇改行尾,sync.sh 预检才拦太晚 判据本身踩了三个坑,都记在注释里: - dict 项 `'env': _vpn_env(),` 单独 ast.parse 会 SyntaxError(没大括号), 真正的注入反而被放过 → 补大括号再解析 - dict 项的键**通常带引号**,正则只写 ^[A-Za-z_] 认不出来 → 改成同时认引号键 - 分隔线注释 `# ------ radvd` 里的 ----- 会被解析成负号表达式 → 按前缀排掉 双向验证:4 种注入形态(赋值/dict项/bool/列表)全部精确报到行号, 基线零误报(排掉了分隔线注释和「# module: (service, action, 中文名)」这类 长得像 dict 项的文档注释)。 三、_dev/dl-verify.py(新增) 从目标机往 Windows 拉大产物时发现的坑,记成脚本省得下次重踩: - `ssh host 'cat f' > out` 在 Windows 上做**文本模式换行转换**,二进制被破坏 (实测 deb 少 4 字节,sha256 直接对不上)→ 走 base64 再本地解码 - Windows Python 看不到 Git Bash 的 /tmp,必须给 C:/ 绝对路径 - scp 传完一定要判 sha256 —— scp/ssh 都可能「返回 0 却落地 0 字节」 - 落地走 .part + os.replace,避免写一半失败留下半个产物 顺带修了 build-docker.sh 里一处路径笔误 (packaging/docker/packaging/docker/DOCKER-GUIDE.md)和步骤编号 1/3→1/4。
106 lines
5.4 KiB
YAML
106 lines
5.4 KiB
YAML
# =============================================================================
|
||
# Drouter —— Docker Compose 编排
|
||
#
|
||
<!-- TEMPLATE-NOTE:BEGIN -->
|
||
# ⚠️ 这是**模板**,__VERSION__ 是占位符,不要直接拿去用。
|
||
# 发版时由 packaging/build-docker.sh 渲染成 dist/docker-compose.yml
|
||
# (版本号从 packaging/VERSION 读)。改版本只需改那一个文件。
|
||
<!-- TEMPLATE-NOTE:END -->
|
||
#
|
||
# 用法:
|
||
# docker load -i drouter-__VERSION__-docker.tar
|
||
# docker compose up -d
|
||
# 浏览器打开 https://<宿主IP>:8443/
|
||
#
|
||
# ⚠️ 先读这三条,否则会踩坑:
|
||
#
|
||
# 1) 必须是 network_mode: host
|
||
# 容器要直接读写宿主网络接口和 nftables 规则,bridge 模式下看到的是
|
||
# 容器自己的网络命名空间,读不到真实网卡,也管不了宿主的 NAT。
|
||
#
|
||
# 2) NET_ADMIN 不能省
|
||
# 少了它 nft 操作会报 "Operation not permitted",防火墙页直接失效。
|
||
# 实测:加上之后 /api/nft 正常返回真实规则集。
|
||
#
|
||
# 3) 这是「体验 / 调试」形态,不建议当主路由
|
||
# 容器里没有 systemd,服务管理页会显示 active: unknown(优雅降级,不是 bug),
|
||
# 且无法持久化 systemd 单元。真正长期当路由器跑请用 .deb 装到物理机/虚拟机上。
|
||
# =============================================================================
|
||
|
||
services:
|
||
drouter:
|
||
# 镜像从 tar 加载后即为这个名字。若你改过标签,这里同步改。
|
||
image: drouter:__VERSION__
|
||
|
||
# 固定容器名,方便 docker exec / logs 直接引用
|
||
container_name: drouter
|
||
|
||
# host 网络是硬要求,见文件头说明
|
||
network_mode: host
|
||
|
||
# ── 权限 ───────────────────────────────────────────────────────────
|
||
# 这里**不用** privileged(过度授权)。只给真正需要的能力:
|
||
cap_add:
|
||
- NET_ADMIN # nft / iptables / 路由表 / 接口配置
|
||
- NET_RAW # ping / traceroute 等原始套接字探测
|
||
- NET_BIND_SERVICE # 绑定 8443(<1024 的端口才严格需要,这里保守给上)
|
||
# 若你想省事、且接受更大权限面,可以注释掉上面三行改用:
|
||
# privileged: true
|
||
|
||
# ── 端口 ───────────────────────────────────────────────────────────
|
||
# network_mode: host 下 ports 会被忽略,端口由 /etc/drouter/web-port 决定。
|
||
# 这里写出来只是**文档作用**,让 `docker compose config` 能看出监听什么。
|
||
expose:
|
||
- "8443" # HTTPS 管理面板
|
||
- "8080" # 备用 HTTP(默认关闭,可在「系统设置」里开)
|
||
|
||
# ── 持久化 ─────────────────────────────────────────────────────────
|
||
# 这四个目录**必须**挂出来,否则 docker compose down 一次配置就全丢了。
|
||
volumes:
|
||
# 配置核心:settings、web-port、active-theme、证书索引
|
||
- drouter-etc:/etc/drouter
|
||
# 运行时数据:SQLite 库、流量统计
|
||
- drouter-data:/opt/drouter/data
|
||
# 配置快照:出问题时的回滚依据
|
||
- drouter-snapshots:/opt/drouter/snapshots
|
||
# 日志
|
||
- drouter-log:/var/log/drouter
|
||
|
||
# ── 环境变量 ───────────────────────────────────────────────────────
|
||
environment:
|
||
TZ: Asia/Shanghai
|
||
# Web 端口只在**首次启动**时播种进 /etc/drouter/web-port。
|
||
# 之后想改端口,请到「系统设置」界面改 —— 别再改这里的环境变量,
|
||
# 否则会出现「界面里改了却没生效」的困惑(环境变量优先级高于配置文件)。
|
||
DROUTER_WEB_PORT: "8443"
|
||
|
||
# ── 启动策略 ───────────────────────────────────────────────────────
|
||
# unless-stopped:重启宿主后自动拉起,但用户手动 stop 后不会自己回来
|
||
restart: unless-stopped
|
||
|
||
# ── 健康检查 ───────────────────────────────────────────────────────
|
||
# /api/health 是免鉴权接口,适合探活。
|
||
# ⚠️ 面板走 HTTPS 且用自签证书,curl 必须加 -k,否则永远 unhealthy。
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "PORT=$(cat /etc/drouter/web-port 2>/dev/null || echo 8443); curl -fsSk --max-time 4 https://127.0.0.1:${PORT}/api/health >/dev/null 2>&1 || exit 1"]
|
||
interval: 30s
|
||
timeout: 5s
|
||
start_period: 20s
|
||
retries: 3
|
||
|
||
# ── 日志 ───────────────────────────────────────────────────────────
|
||
logging:
|
||
driver: json-file
|
||
options:
|
||
max-size: "10m"
|
||
max-file: "3"
|
||
|
||
# =============================================================================
|
||
# 命名卷
|
||
# =============================================================================
|
||
volumes:
|
||
drouter-etc:
|
||
drouter-data:
|
||
drouter-snapshots:
|
||
drouter-log:
|