openresty使用
docker.io/openresty/openresty:latest
sed -i 's/deb.debian.org/mirrors.aliyun.com/g' /etc/apt/sources.list
/etc/openresty/nginx.conf
/etc/nginx/conf.d/default.conf
docker cp ./default.conf opresty:/etc/nginx/conf.d/default.conf
access_by_lua_file:指定一个 Lua 文件,在 access 阶段执行该文件中的 Lua 代码。
content_by_lua_block:在 content 阶段执行一段 Lua 代码块。
content_by_lua_file:指定一个 Lua 文件,在 content 阶段执行该文件中的 Lua 代码。
header_filter_by_lua_block:在 header_filter 阶段执行一段 Lua 代码块,用于修改响应头。
header_filter_by_lua_file:指定一个 Lua 文件,在 header_filter 阶段执行该文件中的 Lua 代码。
body_filter_by_lua_block:在 body_filter 阶段执行一段 Lua 代码块,用于修改响应体。
body_filter_by_lua_file:指定一个 Lua 文件,在 body_filter 阶段执行该文件中的 Lua 代码。
log_by_lua_block:在 log 阶段执行一段 Lua 代码块,用于自定义日志记录。
log_by_lua_file:指定一个 Lua 文件,在 log 阶段执行该文件中的 Lua 代码
vscode扩展
# 适用于nginx语言环境, 可以格式化
hangxingliu.vscode-nginx-conf-hint
限流demo https://opm.openresty.org/package/openresty/lua-resty-limit-traffic
# nginx.vh.default.conf -- docker-openresty
#
# This file is installed to:
# `/etc/nginx/conf.d/default.conf`
#
# It tracks the `server` section of the upstream OpenResty's `nginx.conf`.
#
# This config (and any other configs in `etc/nginx/conf.d/`) is loaded by
# default by the `include` directive in `/usr/local/openresty/nginx/conf/nginx.conf`.
#
# See https://github.com/openresty/docker-openresty/blob/master/README.md#nginx-config-files
#
# 设置限流空间
lua_shared_dict my_limit_req_store 100m;
server {
listen 8099;
#server_name localhost;
#charset koi8-r;
access_log /tmp/host.access2.log;
error_log /tmp/error2.log;
location / {
content_by_lua_block {
error_log file [level];
}
access_by_lua_block {
local limit_req = require "resty.limit.req"
-- req/sec, and reject any requests exceeding 300 req/sec.
local lim, err = limit_req.new("my_limit_req_store", 1, 5)
if not lim then
ngx.say("lim error")
return ngx.exit(500)
end
-- the following call must be per-request.
-- here we use the remote (IP) address as the limiting key
local key = ngx.var.binary_remote_addr
local delay, err = lim:incoming(key, true)
if not delay then
if err == "rejected" then
ngx.say("rejected 503")
return ngx.exit(503)
end
ngx.say(err)
return ngx.exit(500)
end
-- 延迟
-- if delay >= 0.001 then
-- the 2nd return value holds the number of excess requests
-- per second for the specified key. for example, number 31
-- means the current request rate is at 231 req/sec for the
-- specified key.
-- local excess = err
-- the request exceeding the 200 req/sec but below 300 req/sec,
-- so we intentionally delay it here a bit to conform to the
-- 200 req/sec rate.
-- ngx.sleep(delay)
-- end
}
root /usr/local/openresty/nginx/html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
}
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root /usr/local/openresty/nginx/html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
使用防火墙 registry.cn-hangzhou.aliyuncs.com/jcleng/openresty-waf:latest
# 防火墙: https://github.com/codiy1992/lua-resty-waf
### 获取配置
GET http://adhome.2011101.xyz:1122/waf/config
Authorization: Basic d2FmOlRUcHNYSHRJNW13cQ==
### 更新规则和配置
POST http://adhome.2011101.xyz:1122/waf/config
Authorization: Basic d2FmOlRUcHNYSHRJNW13cQ==
Content-Type: application/json
opm安装额外的依赖
# 下载到当前目录
wget https://raw.githubusercontent.com/openresty/opm/master/bin/opm
chmod +x ./opm
# 模块市场
https://opm.openresty.org/package/tokers/lua-resty-requests/
#
mkdir -p ./vendor
./opm --install-dir=./vendor get \
ledgetech/lua-resty-http \
fffonion/lua-resty-openssl
# 使用时指定到lualib目录
lua_package_path "/home/jcleng/work/mywork/podmanserver/lua/vendor/lualib/?.lua;;";
nginx.confhttps://gitee.com/jcleng/openresty_docker_balancer.git
# 设置日志等级
error_log logs/error.log info;
events {
worker_connections 1024;
}
http {
lua_shared_dict podman_upstreams 10m;
lua_package_path "/usr/local/openresty/lualib/?.lua;;/home/jcleng/work/mywork/podmanserver/lua/vendor/lualib/?.lua;;";
default_type application/json;
init_worker_by_lua_block {
ngx.log(ngx.INFO, "✅init_worker_by_lua_block")
local cjson = require("cjson")
local http = require("resty.http")
ngx.log(ngx.INFO, "✅")
-- 每 5 秒拉取容器列表
local ok, err = ngx.timer.every(5, function()
local httpc = http.new()
local ok, err = httpc:connect("unix:/var/run/docker.sock")
if not ok then
ngx.log(ngx.ERR, "连接失败: ", err)
return
end
local path = "/version"
-- Send an HTTP GET request to the Docker daemon via the socket
local res, err = httpc:request({
path = path,
method = "GET",
headers = {
["Host"] = "localhost" -- Host header is required for HTTP 1.1
}
})
local body, err = res:read_body()
-- ngx.log(ngx.ERR, "❌请求失败: ", body)
local res_version, err = cjson.decode(body)
-- 获取容器列表
local res_containers, err = httpc:request({
path = "http://127.0.0.1/v" .. res_version.ApiVersion .. "/containers/json?filters=%7B%22label%22%3A%20%5B%22openresty.enable%3Dtrue%22%5D%7D",
method = "GET",
headers = {
["Host"] = "localhost"
}
})
local body_containers, err = res_containers:read_body()
-- 解析容器列表
local containers, err = cjson.decode(body_containers)
if not containers then
ngx.log(ngx.ERR, "JSON解析失败")
return
end
-- 提取IP和端口,存入共享内存
local upstreams = {}
for _, c in ipairs(containers) do
if c.NetworkSettings and c.NetworkSettings.Networks['openresty-proxy-net'].IPAddress then
table.insert(upstreams, c.NetworkSettings.Networks['openresty-proxy-net'].IPAddress .. ":80")
end
end
-- 存入共享字典
ngx.shared.podman_upstreams:set("api.example.com", cjson.encode(upstreams))
ngx.log(ngx.INFO, "刷新上游节点成功: ", #upstreams, " 个")
end)
}
server {
listen 80;
server_name api.example.com;
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
}
}
upstream backend {
server 127.0.0.1:8080;
balancer_by_lua_block {
ngx.log(ngx.INFO, "✅balancer_by_lua_block")
local balancer = require("ngx.balancer")
local cjson = require("cjson")
local dict = ngx.shared.podman_upstreams
-- 从共享字典获取节点列表
local peers_str = dict:get("api.example.com")
ngx.log(ngx.INFO, "✅peers_str", peers_str)
local peers = cjson.decode(peers_str)
-- 4. 【正确的轮询算法】跨 worker 共享状态
local current, _ = dict:incr("balancer_round_robin_idx", 1, 0)
local idx = (current % #peers) + 1 -- Lua 数组从 1 开始
local peer = peers[idx]
ngx.log(ngx.INFO, "✅ 选中节点[", idx, "]: ", peer)
-- 5. 解析 IP:端口
local host, port = peer:match("^([^:]+):(%d+)$")
if not host or not port then
ngx.log(ngx.ERR, "❌ 节点格式错误: ", peer)
return ngx.exit(503)
end
-- 6. 设置当前转发的后端节点(核心!)
local ok, set_err = balancer.set_current_peer(host, tonumber(port))
if not ok then
ngx.log(ngx.ERR, "❌ 设置后端节点失败: ", set_err)
return ngx.exit(503)
end
}
}
}