Skip to content

构建:补一份服务端 musl 静态包的构建配方 - #426

Open
84593320z wants to merge 2 commits into
aimod-cc:betafrom
84593320z:musl-static-server
Open

84593320z wants to merge 2 commits into
aimod-cc:betafrom
84593320z:musl-static-server

Conversation

@84593320z

Copy link
Copy Markdown

这个 PR 做什么

给服务端补一份 musl 静态构建配方:

  • .github/workflows/build-musl-server.yml —— 用 cargo-zigbuild 出 aarch64 / x86_64 的 musl 静态包;
  • docs/build-musl-server.md —— 为什么值得出、CI 与本机两种编法、验证命令、Windows 交叉编译的坑。

产物命名沿用现有规则,方便被现有安装/更新脚本直接消费:

agent2api-server-linux-arm64-musl.tar.gz        (+ .sha256,sha256sum 格式)
agent2api-server-linux-amd64-musl.tar.gz        (+ .sha256)

为什么要这个变体

现有 agent2api-server-linux-arm64.tar.gz 是 glibc 动态链接,下面三类环境会卡住:

环境 症状 根因
Alpine / distroless / 精简容器 报 no such file or directory,但 file 明明显示是合法 ELF 缺 /lib/ld-linux-aarch64.so.1,内核找不到 PT_INTERP 指的解释器
Android(Magisk / KernelSU 模块) 起不来;勉强起来后所有上游请求 dns error 同上;且 glibc 解析器硬读 /etc/resolv.conf,Android 上那个文件不存在或不归本服务管
宿主 glibc 比构建机旧 GLIBC_2.xx not found 动态链接的固有约束

musl 静态构建一次消掉这三个:无 PT_INTERP、不需要 loader、不链接宿主 libc、单文件。

为什么只在 workflow_dispatch 上跑

本仓库的构建已整体搬到构建仓库,推 tag 只跑那个十几秒的派发 job —— 这条边界我不想碰。所以这份工作流不挂 tag 触发,只有手动点:

Actions → build-musl-server → Run workflow

等配方在真实发版节奏里验证过,直接把文件搬到 Agent2Builder/agent2api-releases、改成跟 repository_dispatch 一起跑就行,源仓库这边删掉即可。

实测数据(本机交叉编译 + 真机跑过)

在 Windows 上用 stable-x86_64-pc-windows-gnu + aarch64-unknown-linux-musl + zig 0.17(zig 当 C 交叉编译器)编出:

14,254,176 字节
ELF 64-bit LSB executable, ARM aarch64, statically linked, stripped
PT_INTERP: 无

装进一个 Android 的 Magisk 模块里跑通了:进程 maps 里没有任何 .so,cmdline 直接就是二进制路径(不经过 ld.so),/health、/v1/models、/v1/chat/completions 全部 200。

顺带一个有意思的对照:某台 Android 的内核会拦 AAAA 查询(sendto 返回 EPERM),glibc 的 getaddrinfo(AF_UNSPEC) 因此整次 EAI_AGAIN 全挂;musl 把 A 与 AAAA 塞进同一个 UDP 包发出,不受影响,AF_UNSPEC 正常返回。这算是静态 musl 在恶劣网络环境下的一个意外好处。

已知差异(写进文档了,这里重复一遍)

  • 没有 NSS 模块,也没有 /etc/nsswitch.conf;musl 解析器直接读 /etc/resolv.conf,hosts 走内置表。本项目只用 getaddrinfo 做 A/AAAA,不受影响。
  • 体积从 ~9MB 涨到 ~14MB(静态链接把 musl 编进去)。
  • musl 的 /etc/resolv.conf 路径是编译期常量。将来若真要支持「解析器配置路径可配」,建议单独开 PR 加 AGENT2API_RESOLV_CONF,本 PR 不碰代码逻辑。

验证方式

# 本地
cd desktop-tauri/src-tauri
cargo zigbuild --release -p agent2api-server --target aarch64-unknown-linux-musl
readelf -l target/aarch64-unknown-linux-musl/release/agent2api-server | grep -c INTERP   # 0

CI 里同样的断言写进了「自检」那一步,产物一旦是动态链接会直接失败,不会静默发出去。

🤖 本条回复由 AI Agent 生成

现有 agent2api-server 只有 glibc 动态链接产物,在 Alpine / distroless /
Android(Magisk 模块)这类没有 /lib/ld-linux-* 的环境里连解释器都找不到;
glibc 解析器又硬读 /etc/resolv.conf,而这些环境里那个文件要么不存在、
要么不归本服务管。

改法:新增 .github/workflows/build-musl-server.yml,用 cargo-zigbuild 出
aarch64 / x86_64 的 musl 静态产物(单文件、无 PT_INTERP,约 14MB),
产物命名沿用现有规则 agent2api-server-linux-{arm64,amd64}-musl.tar.gz(.sha256),
容器内一键更新那边把 update_asset 指过来即可。

这份工作流刻意只允许 workflow_dispatch 手动触发:本仓库的构建已整体搬到
构建仓库,推 tag 只跑派发 job,不应该因为加了这个文件就变成「推 tag 开
构建机」。等配方验证稳定后直接搬去构建仓库即可。

docs/build-musl-server.md 记了为什么值得出这个产物、CI 与本机两种编法、
验证命令,以及 Windows 上交叉编译的两个坑(mingw 工具链、zig 转发 shim)。
仓库 .cargo/config.toml 里 target-dir 已指到仓库根的 target/,工作流却按
src-tauri/target/<triple>/release 去找二进制 —— 第一次真跑就挂在「自检」那一步。
改成从 cargo metadata 读 target_directory,顺带在找不到文件时给出明确报错。
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant