openresty,lua,shell执行服务器脚本
- 为什么不直接通过==php==来调用系统命令而单独写一个监控脚本呢?
- 关于监控脚本
- 为什么用==openresty/ngx_lua==
- 怎么做?
- 1.下载安装麻省理工==Juce==版的 ==lua_resty_shell==
- 2.下载安装 ==sockproc==
- 3. 编写lua脚本
最近安装了openresty ,想做一个通过git各大代码托管平台提供的webhook实现自动部署的功能。以前的实现方式是服务器暴露一个接口(php写的)给托管平台,webhook访问后接口会做一个修改或更新文件的动作,同时服务器上部署一个监控该文件的脚本,一旦检测到文件更新就调用系统的命令,比如 git pull 及其他命令进行项目更新和构建。
为什么不直接通过php来调用系统命令而单独写一个监控脚本呢?
首先是权限的问题,php无论是以php-fpm还是apache模块,一般都会用单独的用户来运行,这是出于安全的考虑,这个用户对项目目录也没有写入的权限,除了部分特殊的目录,比如上传目录才有写权限。所以远程仓库的更新没有办法直接写入到本地。
其次也是因为安全的原因,线上服务器的php.ini的设定都会禁用危险的 exec 、system之类的用来调用shell 命令的函数。
关于监控脚本
windows上可以写一个批处理并加入开机启动,linux上有inotify,后来我还发现了可以使用nodemon实现跨平台。很多人对nodemon的印象还是停留在 javascript上面,特别是前端开发和node.js用得比较多,其实它也可以执行非js文件,比如shell script,python 脚本等等,非常好用的一个工具。
为什么用openresty/ngx_lua
上面的解决方案的缺点很明显,又是php,又是nodemon,还要指定一个监控文件,要依赖的东西太多了,结构上非常松散,也不利于迁移和重用,但是如果用openresty, 只要集中在lua脚本就可以了,加上少量的nginx配置,如果简单粗暴一些,甚至可以直接写在nginx配置里。
怎么做?
- 下载安装麻省理工Juce版的 lua_resty_shell
- 下载安装 sockproc
- 编写lua脚本
1.下载安装麻省理工Juce版的 lua_resty_shell
openresty 有一个默认lualib目录,在 MacOS 上位于 /usr/local/Cellar/openresty/1.19.3.1_1/lualib,这个目录的作用是如果脚本里要引用一个包,比如require “resty.shell” ,映射到磁盘的文件,点会被转化为 “/”,lua会在此目录搜索搜索并实际匹配到这个文件:/usr/local/Cellar/openresty/1.19.3.1_1/lualib/resty/shell.lua
你可以直接把 juce版lua_resty_shell 克隆下来并将 shell.lua文件放入默认的lualib目录,不过这样会替换掉openresty自带的 resty/shell 模块,不建议这样做,可以建立一个单独的目录,这里是用 /Users/falcon/projects/lua/lualib用来存放用户或者第三方的package ,把前面的shell.lua放在这个目录,同时修改nginx.conf,http 加入以下内容:
http {
lua_code_cache off; # 仅开发环境禁用
lua_package_path "/Users/falcon/projects/lua/lualib/?.lua;;";
...
lua_package_path 指令表示lua包搜索的路径,;; 表示默认路径。? 就是require里引用模块的名称,在上文指的是 resty/shell。
2.下载安装 sockproc
按照文档下载编译并启动,可以监听socket,也可以监听端口。btw,我看了文档才知道原来 Macos 上的 telnet 命令是可以按socket来连接的,比linux上的 telnet 可要多才多艺(versatile)😂, linux 上的只能通过端口连接,要连接socket可以通过socat 。
为了方便,我写了个几行小脚本启动:
#!/usr/bin/env bash
/bin/rm /tmp/shell.sock >/dev/null 2>&1
/Users/falcon/cmd/sockproc/sockproc /tmp/shell.sock
3. 编写lua脚本
建立项目路径:/Users/falcon/projects/lua/ngx_script, 新增 test-shell.lua
local shell = require "resty.shell"
local args = {
socket = "unix:/tmp/shell.sock", -- 这是第一步的 unxi socket
}
local status, out, err = shell.execute("uptime", args) -- ls 是想调用的命令,
ngx.header.content_type = "text/plain"
ngx.say("Result:\n" .. out) -- 命令输出结果
修改nginx.conf,server块:
server {
listen 80 default_server;
server_name localhost;
location = /shell {
default_type 'text/html';
content_by_lua_file /Users/falcon/projects/lua/ngx_script/test-shell.lua;
}
}
重启openresty, 访问 http://localhost/shell 会看到以下内容,跟在终端里调用 uptime 命令结果是一样的
Result:
19:28 up 19:57, 3 users, load averages: 2.50 2.98 3.30
说明调用 shell 的测试成功,下面开始编写构建项目自动更新的脚本。