You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does / why we need it?
当前的模块添加/删除采用静态编译,每次升级或者修改模块都需要执行完整的Nginx编译操作,耗时通常长达30分钟,同时在低配置环境下经常出现编译失败情况。
Summary of your change
将原先的静态编译重构为自动识别,在模块支持的情况下默认采用动态编译方式进行引入,只编译对应模块,通过Nginx配置文件方式引入对应模块的加载。
Please indicate you've done the following:
关联 1Panel-dev/appstore#8644 ,关联 #10653
由于涉及到的内容较多,虽然已经进行本地测试通过,但是可能仍然需要团队进一步的测试以确保可靠性。
以下是完整细节:
OpenResty 动态模块支持(.so 本地构建 + load_module 热加载 + 升级自动重编译)
关联 PR:1Panel-dev/appstore(openresty 模板配套改动)。建议 appstore 先合并,面板侧功能依赖模板里的
Dockerfile.modules与模块目录。面向的问题
现在 1Panel 里给 OpenResty 加一个模块(比如 rtmp、web_dav),唯一的路是静态编译:把模块参数拼进
RESTY_CONFIG_OPTIONS_MORE,然后整个镜像从源码重新编译一遍,再重建容器。实测在 4 核 OVH VPS 机器上一次要 27~31 分钟,期间面板任务被占住,最后还要重启容器造成秒级闪断,性能和时间消耗过大。Nginx 从 1.9.11 起支持
load_module动态加载.so,OpenResty 编译时带--with-compat就能做到二进制兼容。只需要用和运行时镜像一致的基线把模块单独编成.so,挂载进容器,写一行load_module,reload 一下就生效了——不重新编译整个 OpenResty,也不重启容器。可以大幅度降低修改模块后的编译等待时间和性能占用。这个 PR 实现的内容:
.so,校验通过后热加载,容器不重启(实测构建前后容器 StartedAt 不变)实现方式
模块配置储存
appstore 侧每个 openresty 版本目录下新增两份文件:
build/module.catalog.json:模块目录,描述每个模块怎么构建——源码准备脚本(script)、编译期 apt 依赖(packages)、configure 参数(params)、加载顺序(loadOrder)。目前收录自带的 5 个:ngx_brotli、rtmp、web_dav、geoip2、http_substitutions_filterbuild/module.json:安装时落到应用目录的 per-install 配置,初始内容与 catalog 一致,之后用户在面板上的改动(启用/构建方式/参数)都写在这里面板后端所有模块操作都围绕应用目录下的
module.json进行,catalog 只作为初始模板。仓库根新增scripts/check-openresty-modules.sh校验两者逐字节一致(这两个文件现在是人工同步的,容易改一个忘一个),并配了一个独立的 GitHub workflow 在 openresty 相关变更时自动跑。动态构建链路
核心是
agent/app/service/nginx_module.go。一次动态构建的流程:docker image inspect拿,失败回退宿主机架构并记 WARNING)、镜像 Id、Dockerfile.modules的 SHA-256,算出 target key。镜像或者 builder 变了,key 就变,旧构建自然标记为 stale,触发重编docker build跑Dockerfile.modules,它就是FROM 1panel/openresty:<版本>(ABI 基线和运行时完全一致)加一层编译环境,configure 用--with-compat,模块参数里的--add-module=会被规范化成--add-dynamic-module=。产物从容器里拷出来,带 SHA-256 清单nginx -t,再按 loadOrder 把所有启用模块的load_module拼起来做一次联合nginx -t——防止模块之间符号冲突conf/modules-enabled/1panel-module-<loadOrder>-<模块名>.conf(写前快照,失败可还原),容器内nginx -t通过后nginx -s reload。全程容器不重启回滚语义:构建失败时旧的 ready 构建和旧配置原样保留,模块行只多一个失败标记和原因;managed conf 写入/校验失败时还原到写入前的快照。(见测试一节)。
签名兼容性潜在问题
最初
Dockerfile.modules的 configure 参数漏了--with-http_realip_module --with-http_dav_module,结果编出来的.so在运行时load_module全部被 nginx 拒绝(is not binary compatible)——nginx 动态模块校验 configure 签名,第 29/31 位对不上就拒载。已进行修正,三个版本的 builder 与运行时镜像签名一致,测试脚本里有针对这个错误的专项检查(not binary compatible出现即 FAIL)。另一个安全相关的点:模块 params 用 go-shellwords 解析,但这个库遇到未加引号的
;&|<>会静默截断而不是报错,原来写在解析后的逐参数检查根本摸不到这些字符。现在在解析前对原始串做元字符预检直接拒绝(parseDynamicModuleParams),对应测试TestNormalizeDynamicModuleParams。auto 模式与回退语义
构建方式里
auto的含义是"优先动态,动态走不通回退静态兜底":auto会回退。用户显式选dynamic而构建失败时,只报错不切换static,lastError里保留动态失败原因(UI 上能直接看到,用户可以随时改回 auto)升级链路的踩的三个坑(实测发现,已修)
拿官方仓库真实版本做升级测试时撞到三个问题,已经进行修复:
buildDynamicNginxModules,而它第一步就要读build/Dockerfile.modules——老安装没这个文件,哪怕一个模块都没启用过,升级也直接炸。现在没有动态构建任务时整个 target 解析直接跳过build/tmp对不上(tarball 版本不匹配),构建报错把升级拖死。现在降级为 WARNING:升级继续,动态模块保持下线,面板里能看到原因。显式在面板点"构建"仍然是明确报错,不会静默handleUpgradeCompose只从旧 compose 保留deploy/restart,官方新 compose 没有./modules、./conf/modules-enabled两个挂载,升级后容器里根本看不到.so——而且因为 include 是 glob,nginx -t照样通过,属于毫无征兆的静默失效。现在升级时会把旧 compose 里这两条挂载合并到新 compose第 2 点有个实测时发现的细节值得记录:只要安装目录里的
Dockerfile.modules还在,且其RESTY_VERSION与新版本上游 OpenResty 版本一致(比如 1.31.1.1-0 → 1.31.1.1-2-1,上游都是 1.31.1.1),升级时动态模块其实能正常按新镜像重编并加载——已经在真实官方包上验证通过。前端
网站 → OpenResty 设置 → 模块页改为三列:构建方式 / 构建状态(失败带原因 tooltip)/ 兼容性(compatible / stale / static)。构建抽屉支持勾选多个模块一起构建、选 apt 镜像源。编辑抽屉里 auto 的文案写的是"自动(动态构建)",避免误解成"自动检测"。
测试
环境:AlmaLinux 10(4C8G),Docker CE 29.6.2,面板官方 v2.2.3 安装后替换为 PR 编译的二进制,OpenResty 用应用商店正常安装。
单元测试:
agent下go test ./app/service -run 'Module'12 个全过,go vet零错误。覆盖参数规范化、元字符预检、构建记录查找、失败回滚保留旧构建、target 缺 builder 哨兵、compose 挂载合并、回退判定与翻转。构建器集成测试(
scripts/openresty-modules/test-builder.sh,不依赖面板,直接从 appstore 模板构建):三个版本(1.27.1.2-5-1-focal / 1.29.2.5-0-noble / 1.31.1.1-0-noble)× 5 个模块全部 PASS,含单模块加载、loadOrder 联合加载、起容器热 reload、负例回滚,每个.so有 SHA-256 记录,全程无not binary compatible。面板端到端:
modules/下有.so+ manifest,modules-enabled/生成 load_module 配置,容器内nginx -t通过,构建前后容器 StartedAt 不变modules-enabled/文件名按 loadOrder 数字前缀排序exit 1强制重新构建,任务失败,旧.so与旧配置完整保留,nginx -t照常通过nginx -t正常升级端到端(共四轮):
nginx -T可见 4 条load_module),compose 挂载保留--with-debug的模块(动态必然拒绝,静态可编),构建 → 日志 WARNING 指名模块 → 落盘 static → 27 分钟编译期旧容器持续在线 → 成功后切换,nginx -V含--with-debug;升级路径同场景同样验证通过诊断:
scripts/openresty-modules/diagnose-install.sh在回滚后和升级后各采集一次,8 项检查全过,failed_checks=0。它会核对产物校验和、managed conf、compose 配置、只读挂载、镜像一致性、容器状态与nginx -t。复测方式:装一台 Linux + Docker,按
scripts/openresty-modules/README.md跑./test-builder.sh --appstore <appstore目录>即可复现构建器测试矩阵;面板侧按 HANDOVER 文档的阶段 5-7 操作(面板 API 与 UI 操作等价)。需要评审注意的点
resolveNginxModuleTarget的 target key 组成:版本 + 架构 + 镜像 Id + builder digest,任何一项变化都会触发全量重编,这是有意为之(宁可多编不可错载)reconcileDynamicNginxModuleConfig的快照/还原时序:先校验再写 conf、写失败还原、nginx -t失败也还原app_utils.go)里降级与回退的状态迁移:缺 builder → 降级继续;动态失败 → auto 翻转 static 交给后续 buildNginxRESTY_CONFIG_OPTIONS_MORE进全量编译libbrotli-dev(focal 镜像无头文件)尚未实现的部分
1.21.4.3-3-3-focal这个老版本没加模块文件。升级到/从它升级会走降级路径(升级本身不受影响,但动态模块会下线)。回填模板或在文档里直接声明buildModeAuto等新增 key(回退显示英文),需要进行翻译补充回滚
面板二进制与
/opt/1panel/db有备份可直接还原;OpenResty 侧用面板"重建"即回官方模板。