Files
liuzhuohua 6df3a94b90 适配 arm64 Debian(Armbian 26.8.1 trixie):去掉架构假设
有用户要在 arm64 的 Debian 上跑 drouter。这一轮只对一个发行版做了适配
—— Armbian 26.8.1 trixie(Debian 13.6)/ aarch64 / 内核 6.18.35-ophub
(Amlogic S912 板),别的 arm64 发行版未验证,验证范围与实测数据全部
写在 docs/07-arm64-适配说明.md。

改掉的四处 x86 假设:

1. helper._read_bios():ARM 板既无 /sys/firmware/efi 也无 /sys/class/dmi,
   原代码把它们一律落到 else 分支,系统概览显示「传统 BIOS」(错的,
   这类机器根本没有 BIOS)。新增设备树分支,判据顺序 EFI → 设备树 → BIOS
   (树莓派 4 这类两可的机器要优先认 EFI);读 /proc/device-tree 与
   /sys/firmware/devicetree 两个候选路径,compatible 按 NUL 切开取第一条;
   没有 DMI 厂商时拿设备树板名顶上,厂商格不再空白。返回结构加 fw_type
   / is_dt / compat,旧字段一个没动。

2. update.py:离线包资源名原先写死 -offline-amd64,arm64 机器点一键更新
   会下载 x86 离线包,传几十 MB 才在装包阶段炸依赖。改为按
   dpkg --print-architecture 拼名(_deb_arch / build_assets),并为带架构
   后缀的附件在下载前先拿官方 SHA256SUMS 核对存在性,没有就明确报错。

3. packaging:离线包说明里两处写死的 amd64 换成 $ARCH(包名早就是变量拼的,
   但包里那份 README 还在教用户核对 amd64);build-docker.sh 新增可选的
   第 2 个参数 [arch],交叉构建时加 --platform 并给标签加 -<arch> 后缀,
   不传第二参数时行为与改动前逐字节一致。

4. web/i18n.js:给新增的「设备树 (Device Tree)」展示串登记英文,
   否则英文界面漏中文。

配套:
- _dev/t-arch.py(31 条判据)+ _dev/t-arch-inject.py(20 例反向验证)。
  反向验证抓出一条假绿:i18n 词条的 n/d 判据用了 300 字符松弛窗口,
  会跨到下一条词条,删掉本词条的 d 之后照样绿 —— 已收紧为本词条花括号内。
- _dev/run-static.py 的 EXCL 补上 t-update-inject —— 它名字也是 t- 前缀,
  之前一直被全量回归自动执行,会在回归过程中反复改写 backend/ 与 web/。
- devtools/verify-arm64.py:只读验收脚本,方便他人在自己的板子上复验。
- README 支持矩阵里 arm64 从「理论可用」改为「已实测 1 个发行版」。

本机全量静态回归 71 个检查器 / 0 失败;目标机上只读验证 12 条全通
(构建 753 396 字节的 deb / depcheck 73 项 / 8 个渲染模块 / 架构感知清单)。
目标机未安装 drouter,未启用任何服务,未改动网络。
2026-10-16 06:16:31 +08:00

122 lines
5.4 KiB
Bash
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.
#!/bin/bash
# =============================================================================
# 构建 drouter 的 Docker 镜像
#
# bash packaging/build-docker.sh [tag] [arch]
#
# 产物:drouter:<tag> (arch 省略 / 与本机架构相同时)
# drouter:<tag>-<arch> (交叉构建时,标签带架构后缀)
#
# arm64 适配(2026-10-16):Debian 13 的 arm64 机器也能跑 drouter
# (deb 是 Architecture: all,纯 Python),镜像自然也该能出 arm64 版本:
# bash packaging/build-docker.sh 1.0.10 arm64
# ⚠️ 交叉构建要靠 buildx/qemu 提供目标架构的执行能力,
# 宿主机没有装 binfmt_misc 会卡在 RUN 那一步;这种机器上请直接跑到 ARM 主机上构建。
#
# 注意:Dockerfile 里 COPY 的是相对路径,所以构建上下文必须是项目根目录。
# =============================================================================
set -euo pipefail
HERE="$(cd "$(dirname "$0")/.." && pwd)"
# 版本号唯一真源是 packaging/VERSION(见 build-deb.sh 里的说明)
VF="$HERE/packaging/VERSION"
[ -f "$VF" ] || { echo "缺少 $VF(版本号唯一真源)"; exit 1; }
TAG="${1:-$(tr -d ' \t\r\n' < "$VF")}"
# 目标架构。省略时按本机 dpkg 架构处理 —— 那等于「原生构建」:
# 不加 --platform,标签也不带后缀,产物与改动前**逐字节一致**。
DPKG_NATIVE="$(dpkg --print-architecture 2>/dev/null || echo amd64)"
ARCH="${2:-$DPKG_NATIVE}"
command -v docker >/dev/null 2>&1 || { echo "需要 docker"; exit 1; }
# 交叉构建(目标架构 ≠ 本机架构)才加 --platform 与标签后缀。
# 原生构建硬塞 --platform 反而会拖慢(docker 可能跳过本地缓存层)。
if [ "$ARCH" = "$DPKG_NATIVE" ]; then
PLATFORM_ARG=()
IMGTAG="$TAG"
echo "== 目标架构:$ARCH(与本机一致,原生构建)=="
else
PLATFORM_ARG=(--platform "linux/$ARCH")
IMGTAG="$TAG-$ARCH"
echo "== 目标架构:$ARCH(交叉构建,标签后缀 -$ARCH)=="
fi
echo "== 1/4 构建前自测(避免把坏代码打进镜像)=="
python3 - <<'PY'
import ast, glob
bad = 0
for f in sorted(glob.glob('backend/*.py')):
try:
ast.parse(open(f, encoding='utf-8').read()); print(' OK:', f)
except Exception as e:
print(' FAIL:', f, e); bad += 1
raise SystemExit(1 if bad else 0)
PY
command -v node >/dev/null 2>&1 && node --check web/app.js && echo " OK: web/app.js"
echo "== 2/4 构建镜像 drouter:$IMGTAG =="
docker build "${PLATFORM_ARG[@]}" -f "$HERE/packaging/docker/Dockerfile" \
-t "drouter:$IMGTAG" "$HERE"
# 同时打一个带用户名的别名,方便日后直推 Docker Hub / 私有仓库。
# 两个标签指向同一个 image id,不额外占空间。
docker tag "drouter:$IMGTAG" "liuzhuohua/drouter:$IMGTAG"
echo "== 3/4 渲染 Release 附件(docker-compose.yml / DOCKER-GUIDE.md)=="
# 这两个文件是**模板**,里面写的是 __VERSION__ 占位符,不是具体版本号。
# 早先它们直接硬编码版本号,于是每次发版都要手工 sed 一遍 —— 上一版就漏过,
# 附件里带着 drouter:1.0.8,用户拿 1.0.9 的 tar 加载后标签对不上,
# `docker compose up` 直接报「找不到镜像」。所以这里从 VERSION 渲染。
mkdir -p "$HERE/dist"
for f in docker-compose.yml DOCKER-GUIDE.md; do
src="$HERE/packaging/docker/$f"
[ -f "$src" ] || { echo "缺少模板 $src"; exit 1; }
# 两步:① 整块删掉 TEMPLATE-NOTE 标记块(那是给维护者看的「这是模板」提示,
# 留着会让用户看到「1.0.9 是占位符」这种自相矛盾的话);
# ② 再把剩下的 __VERSION__ 换成真实版本号。
# 顺序不能反 —— 先替换的话,标记块里的 __VERSION__ 也会被换掉,
# 删的时候连同「这是模板」的语义一起留在了附件里。
sed '/TEMPLATE-NOTE:BEGIN/,/TEMPLATE-NOTE:END/d' "$src" \
| sed "s/__VERSION__/$IMGTAG/g" > "$HERE/dist/$f"
# 渲染完必须一个占位符都不剩 —— 剩下就说明模板里有漏网的写法
if grep -q '__VERSION__' "$HERE/dist/$f"; then
echo "✘ $f 渲染后仍含 __VERSION__,模板有问题"; exit 1
fi
# 标记块也不能残留(否则说明嵌套写错了,BEGIN/END 没配对)
if grep -q 'TEMPLATE-NOTE' "$HERE/dist/$f"; then
echo "✘ $f 渲染后仍含 TEMPLATE-NOTE 标记"; exit 1
fi
echo " dist/$f ($IMGTAG)"
done
echo "== 4/4 产物 =="
docker images --filter "reference=drouter" --filter "reference=liuzhuohua/drouter"
echo ""
cat <<RUN
运行示例(详见 dist/DOCKER-GUIDE.md):
# 方式 A:docker compose(Release 里附了 docker-compose.yml)
docker compose up -d
# 方式 B:docker run
docker run -d --name drouter --restart unless-stopped \\
--network host \\
--cap-add NET_ADMIN --cap-add NET_RAW \\
-e TZ=Asia/Shanghai \\
-v drouter-etc:/etc/drouter \\
-v drouter-data:/opt/drouter/data \\
-v drouter-snapshots:/opt/drouter/snapshots \\
-v drouter-log:/var/log/drouter \\
drouter:$IMGTAG
导出成 tar(用于分发):
docker save drouter:$IMGTAG liuzhuohua/drouter:$IMGTAG \\
-o dist/drouter-$IMGTAG-docker.tar
说明:
--network host 让容器直接看到宿主机网卡(路由类功能的前提)
NET_ADMIN 允许操作 nftables / 网卡 / 路由表
不需要 --privileged:只要 NET_ADMIN + NET_RAW 就够
默认账号 admin / admin123,登录后请立即修改
RUN