有一应用需动态更新目标的ip和端口,使用nginx/openresty tcp/udp端口转发配合lua扩展很方便实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | stream { lua_shared_dict ups_dict 1m; lua_shared_dict ups_list 1m; lua_add_variable $ups_name ; #当nginx启动或reload时读取配置文件内upstream列表到lua_shared_dict,更新后端的时候判断是否有效 init_by_lua_block { ngx.shared.ups_list:flush_all() local file = "/etc/nginx/stream.conf" local f = io.open(file, "r" ) local content = f:read( "*a" ) f:close() for substr in string.gmatch(content, "upstream%s+([%w-_]+)%s+%{" ) do ngx.log(ngx.WARN, substr) ngx.shared.ups_list: set (substr, 1) end } log_format main '$remote_addr [$time_local] ' '$protocol $status $bytes_sent $bytes_received ' '$session_time "$upstream_addr" ' '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"' ; access_log /run/log/nginx/dns_access.log main; error_log /run/log/nginx/dns_error.log error; #log level: debug, info, notice, warn, error (default), crit, alert, and emerg. upstream default_tcp { server 127.0.0.1:53; server 127.0.0.1:55; } upstream default_udp { server 10.0.1.1:53; server 10.0.2.1:53; } upstream default_udp2 { server 10.0.3.1:53; server 10.0.3.2:53; } upstream test1_tcp { server 127.0.0.1:53; } upstream test1_udp { server 10.0.1.1:53; } upstream test1_udp2 { server 10.0.3.2:53; } upstream test2_tcp { server 127.0.0.1:55; } upstream test2_udp { server 10.0.2.1:53; } upstream test2_udp2 { server 10.0.3.1:53; } server { listen 53000 udp; preread_by_lua_block { assert(not ngx.var.ups_name) local ups = ngx.shared.ups_dict:get( "ups_name" ) if ups ~= nil then ngx.log(ngx.WARN, "udp 53000 use " .. ups .. " upstream" ) ngx.var.ups_name = ups .. "_udp" else ngx.log(ngx.WARN, "udp 53000 use default upstream" ) ngx.var.ups_name = "default_udp" end } proxy_pass $ups_name ; proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接 proxy_connect_timeout 1s; proxy_timeout 5s; } server { listen 53000; preread_by_lua_block { assert(not ngx.var.ups_name) local ups = ngx.shared.ups_dict:get( "ups_name" ) if ups ~= nil then ngx.log(ngx.WARN, "tcp 53000 use " .. ups .. " upstream" ) ngx.var.ups_name = ups .. "_tcp" else ngx.log(ngx.WARN, "tcp 53000 use default upstream" ) ngx.var.ups_name = "default_tcp" end } proxy_pass $ups_name ; #proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接 proxy_connect_timeout 1s; proxy_timeout 5s; } server { listen 53001 udp; preread_by_lua_block { assert(not ngx.var.ups_name) local ups = ngx.shared.ups_dict:get( "ups_name" ) if ups ~= nil then ngx.log(ngx.WARN, "udp 53001 use " .. ups .. " upstream" ) ngx.var.ups_name = ups .. "_udp2" else ngx.log(ngx.WARN, "udp 53001 use default upstream" ) ngx.var.ups_name = "default_udp2" end } proxy_pass $ups_name ; proxy_responses 1; #当返回一个udp数据包时就关闭连接,或proxy_timeout时间内无数据关闭连接 proxy_connect_timeout 1s; proxy_timeout 5s; } server { listen 53001; content_by_lua_block { local sock = assert(ngx.req.socket(true)) local data = sock:receive() local args, err = ngx.decode_args(data, 0) if err == nil then for k,v in pairs(args) do --ngx.say(v) ip = v:match( "(%d+%.%d+%.%d+%.%d+%:%d+)" ) if ip ~= nil then local sus, err = ngx.shared.ups_dict: set (k, ip) if sus then ngx.say( "set upstream sus: " .. k .. "=" .. ip) else ngx.say(err) end end end end } access_log off; } server { listen 53002; content_by_lua_block { local sock = assert(ngx.req.socket(true)) local data = sock:receive() if data then local args, err = ngx.decode_args(data, 0) if err == nil then for k,v in pairs(args) do --ngx.say(v) -- if k == "name" and type(v) == "string" and v:find( "dns" ) then if k == "name" and type(v) == "string" and ngx.shared.ups_list:get(v .. "_udp" ) then local sus, err = ngx.shared.ups_dict: set ( "ups_name" , v) if sus then ngx.say( "set upstream sus: " .. k .. "=" .. v) ngx.log(ngx.WARN, "set upstream sus: " .. k .. "=" .. v) else ngx.say(err) end end end end end } access_log off; } } |
使用nc测试设置nginx转发使用的后端upstream名称:
1 2 3 | nc 127.0.0.1 53002 name=test1 set upstream sus: name=test1 |
也可通过53001端口设置目标ip:port,然后proxy_pass即可。
参考:
https://github.com/openresty/lua-resty-core/blob/master/lib/ngx/balancer.md
https://xiangxianzui.github.io/2017/11/nginx-lua%E5%8A%A8%E6%80%81%E6%94%B9%E5%8F%98upstream/
标签:nginx, openresty, lua, 端口转发, nginx动态更新upstream