雷池nginx t1k插件原理说明及编译流程
原理说明
nginx 将各个功能实现成了相互独立的模块。每个模块可以选择插入到特定的逻辑阶段以进行工作。t1k 模块工作在 ACCESS_PHASE。在这一阶段,t1k 将请求数据转发至检测服务器,并且根据检测服务器返回的检测结果来决定是否放行该请求。
在有动态模块支持的 nginx 版本中(tengine 2.0.0+、nginx 1.9.11+),可以将一个或者多个模块单独编译成一个或者多个 .so 文件。通过增加特定的配置,可以在不用重新编译 nginx 的情况下动态加载模块并执行。
编译流程
tengine <= 2.2.2
tengine 在安装时打包了自身的头文件,通常可以在安装路径(通常是 /usr/local/nginx)的 include 目录下找到。同时 tengine 提供了一个名为 dso_tool 的脚本(/usr/local/nginx/sbin/dso_tool),可以方便的编译生成动态模块。
由于 nginx 需要依赖少数的系统库,因此编译环境需要同客户的nginx运行环境保持一致,在与客户相同的环境下编译安装 tengine 后即可使用 dso_tool 工具来编译 t1k。
dso_tool 是一个使用了 bash 特有语法的 shell 脚本,但是其 shebang 是 #!/bin/sh,因此直接执行可能会遇到报错,需要指定以 bash 执行:
$ bash /usr/local/nginx/sbin/dso_tool -h
-h, --help display this help and exit
-d, --dst=PATH set module installation path
-a, --add-module=PATH external module which will be compiled(absolute path)
-s, --nginx-include=SOURCE set nginx include path(absolute path)
dso_tool 的参数有三个,全都都接绝对路径,其中只有 -a 是必须的,以 t1k-3.4.0 为例,解压 t1k 源码包之后执行如下命令即可完成 t1k 模块的编译:
bash /usr/local/nginx/sbin/dso_tool -a=$PWD/ngx-http-t1k-module-t1k-3.4.0-1e5be1d0
编译完成后可以在 ngx-http-t1k-module-t1k-3.4.0-1e5be1d0/objs/ngx_http_t1k.so 找到编译输出。
tengine >= 2.3.0
2.3.0 以及之后的 tengine rebase 到了 nginx 1.15.9,移除了自己的动态模块实现,直接采用 nginx 提供的动态模块功能。因此编译方法与 1.9.11 版本之后的 nginx 完全相同。
t1k 模块从 19.04.001 开始适配了 2.3.0 的 tengine,因此如果要为 2.3.0 以及之后版本的 tengine 编译动态模块,需要使用 19.04.001 之后版本的 t1k 源码。并且 19.04.001 之后版本的 t1k 对 2.2.2 以及之前版本 tengine 继续保持支持。
注意:2.3.0 的 tengine 在编译动态模块时有个 bug,导致在顶层目录直接 make modules 不能生成 .so 模块,可以直接使用 make 来替代。
nginx >= 1.9.11
nginx 在 1.9.11 版本之后开始支持动态模块。相对于 tengine 的动态模块实现,nginx 的动态模块实现的更为严谨,因此限制也比 tengine 要多。nginx 的动态模块编译需要完整的原始代码树(也就是用户所运行的 nginx 的原始编译代码),当时的 configure 参数,以及当时的编译环境(系统版本、内核版本等需要严格对应)。如果编译时依赖了第三方代码的话(例如第三方 nginx 模块、openssl 等),这些代码也是必须的。对于编译 nginx 的动态模块,保持编译环境的一致性是非常重要的。因为不同的编译环境可能产生不同的头文件,严重时可能导致运行时 nginx 崩溃,因此需要特别小心。
在客户的环境下执行 nginx -V 可以获取到用户环境的 configure 参数。
以 nginx-1.18.0 及 t1k-3.4.0 为例,建立好编译环境后,使用如下命令可以得到动态模块:
cd nginx-1.18.0
./configure <用户的 configure 参数> --add-dynamic-module=../ngx-http-t1k-module-t1k-3.4.0-1e5be1d0
make modules
如果使用 make modules 报错或者没有生成 .so 文件,可以直接执行 make 执行完整编译。
编译得到的 .so 文件位于 nginx 源码目录下的 objs 文件夹内,也可以直接在源码目录使用 find 命令查找:
$ find -name 't1k.so'
./objs/ngx_http_t1k_core_module.so
编译得到的动态模块,通常需要删除掉符号表之后再交付给客户,对于 tengine <= 2.2.2 的编译过程,符号表已经被编译脚本自动删掉了,这里还需要执行以下命令:
strip ./objs/ngx_http_t1k_core_module.so
openresty
由于 openresty 依赖的是标准的 nginx,因此编译过程同 nginx 类似,以 openresty-1.19.3.1 为例:
cd openresty-1.19.3.1
./configure <用户的 configure 参数> --add-dynamic-module=
make
然后使用 find 命令即可找到 t1k 模块的输出位置:
$ find -name 't1k.so'
./build/nginx-1.19.3/objs/ngx_http_t1k_core_module.so
同样需要删除掉符号表:
strip ./build/nginx-1.19.3/objs/ngx_http_t1k_core_module.so
其他相关事项可参考 openresty 编译安装文档 。