nginx-通过lua动态更改upstream

简介:

最近我们搭了一个consul服务,开发同学想要把supervisor的web管理集成到consul中,需要根据url中给定的ip地址动态的加载该机器上的supervisor管理界面,因为服务端机器都在VPC内部,办公网网络不可达,因此不能简单的rewrite url或者做个重定向来解决,因此需要通过反向代理的方式将请求转发给后端机器,并且要实现反向代理服务器的动态更改,由于逻辑比较复杂,所以就用lua脚本来实现了

大致逻辑是这样的

  • upstream获取

    • 因为我们的consul服务通过域名访问,链到supervisor时,url中会有具体的upstream Ip,所以会先从url中看是否能match到ip,这样可以拿到upstream,并返回supervisor首页信息;
    • 当做tailf,start, stop 操作时,因为页面是从supervisor页链过去的,所以可以通过http_referer header来match upstream ip
  • uri获取

    • 当拿到upstream后,从request_uri做字符串截取来拿到uri
  • 然后一些css样式,image可以从本机获取

具体实现如下

location /supervisor/ {
    set $query_uri "";
      #一开始从request_uri中把/supervisor/前缀去掉
    if ($request_uri ~* "/supervisor/(.*)") {
        set $query_uri $1;
    }
    set $upstreamhost "";
    rewrite_by_lua_block {
        ngx.var.upstreamhost = string.match(ngx.var.query_uri,"%d+.%d+.%d+.%d+")
        if ngx.var.upstreamhost == nil then
            ngx.var.upstreamhost = string.match(ngx.var.http_referer,"%d+.%d+.%d+.%d+")
        end
        index_start,index_end = string.find(ngx.var.query_uri,ngx.var.upstreamhost)
        if index_end ~= nil then
            tmp_uri = string.sub(ngx.var.query_uri,index_end+1)
            ngx.var.query_uri = tmp_uri
        end
    }
    proxy_pass http://$upstreamhost:8555/$query_uri;
    proxy_redirect http://$upstreamhost:8555 http://consul.url/supervisor/$upstreamhost;
}
location /supervisor/images/ {
    if ($request_uri ~* "/supervisor/(.*)") {
        proxy_pass http://127.0.0.1:8555/$1;
    }
}
location /supervisor/stylesheets/ {
    if ($request_uri ~* "/supervisor/(.*)") {
        proxy_pass http://127.0.0.1:8555/$1;
    }
}

因为在supervisor管理页面clear log的时候,服务器会返回Location header,所以通过proxy_redirect directive来做个重定向,让client(浏览器)还是走consul.server来发送请求,从而避免网络不可达问题

这样从本地办公网访问http://consul.url/supervisor/10.10.10.12就可以不用登陆服务器对服务进行启停及查看日志等操作了

pprof集成

同样再加pprof(go的性能调试工具)的时候,就可以复用这个逻辑了(因为go的pprof端口不一致,所以在url中给了ip:port, match的时候也多改成了"%d+.%d+.%d+.%d+:%d+")

location /debug/pprof/ {
    set $query_uri "";
    if ($request_uri ~* "/debug/pprof/(.*)") {
        set $query_uri $1;
    }
    set $upstreamhost "";
    rewrite_by_lua_block {
        ngx.var.upstreamhost = string.match(ngx.var.query_uri,"%d+.%d+.%d+.%d+:%d+")
        if ngx.var.upstreamhost == nil then
            ngx.var.upstreamhost = string.match(ngx.var.http_referer,"%d+.%d+.%d+.%d+:%d+")
        end
        index_start,index_end = string.find(ngx.var.query_uri,ngx.var.upstreamhost)
        if index_end ~= nil then
            tmp_uri = string.sub(ngx.var.query_uri,index_end+1)
            ngx.var.query_uri = tmp_uri
        end
    }
    proxy_pass http://$upstreamhost/debug/pprof/$query_uri;
}

这样开发从办公环境访问http://consul.url/pprof/10.10.10.12:203就可以对测试、开发环境的go程序进行简单的监控了

改进: ip全部通过url获取

有时开发希望通过命令行直接去看某台机器的pprof debug信息,为了方便粘贴浏览器的url,所以希望能把host地址包含进请求url,所以做了如下改进

location /debug/pprof/ {
    set $query_uri "";
    if ($request_uri ~* "/debug/pprof/(.*)") {
        set $query_uri $1;
    }
    set $upstreamhost "";
    rewrite_by_lua_block {
        ngx.var.upstreamhost = string.match(ngx.var.query_uri,"%d+.%d+.%d+.%d+:%d+")
        if ngx.var.upstreamhost == nil then
            ngx.var.upstreamhost = string.match(ngx.var.http_referer,"%d+.%d+.%d+.%d+:%d+")
        end
        index_start,index_end = string.find(ngx.var.query_uri,ngx.var.upstreamhost)
        if index_end ~= nil then
            tmp_uri = string.sub(ngx.var.query_uri,index_end+2)
            ngx.var.query_uri = tmp_uri
        end
        local new_uri = "/debug/pprof/"..ngx.var.upstreamhost.."/"..ngx.var.query_uri
        --ngx.redirect(new_uri,301)
        ngx.req.set_uri(new_uri)
    }
    proxy_pass http://$upstreamhost/debug/pprof/$query_uri;
}

这样从http://consul.url/pprof/10.10.10.12:203返回的链接查看goroutine信息的时候,浏览器会跳转到http://consul.url/pprof/10.10.10.12:203/goroutine?debug=1

关于多余代码

如果set_uri了,那么下面这句代码看似就显得多余了

if ngx.var.upstreamhost == nil then
    ngx.var.upstreamhost = string.match(ngx.var.http_referer,"%d+.%d+.%d+.%d+:%d+")
end

但是浏览器有个不好的地方就是会缓存重定向,而且单纯的disable cache不管用,因为之前都是跳到http://consul.url/pprof/goroutine?debug=1, 所以即使set_uri, 浏览器仍然不会跳转到新的url,只有先301重定向破坏它的‘记忆’后才可以正常跳转

目录
相关文章
|
5月前
|
存储 缓存 Java
Openresty(lua+nginx)-Guava-Redis做多级缓存
Openresty(lua+nginx)-Guava-Redis做多级缓存
55 1
|
11月前
|
负载均衡 算法 应用服务中间件
Nginx系列教程(08) - Upstream Server 负载均衡
Nginx系列教程(08) - Upstream Server 负载均衡
366 0
浅谈基于openresty(nginx+lua)开发轻量级,按流量控制的灰度模块(下)
浅谈基于openresty(nginx+lua)开发轻量级,按流量控制的灰度模块
127 0
|
5月前
|
网络协议 应用服务中间件 nginx
解决 nginx 启动错误host not found in upstream "XXXX.com“
在前置机上利用nginx进行反向代理的时候,我们会配置proxy_pass。在启动nginx的会报如下错误:host not found in upstream "XXXX.com“
3085 0
|
2月前
|
应用服务中间件 nginx
[nginx]lua读取请求体
[nginx]lua读取请求体
|
2月前
|
缓存 应用服务中间件 nginx
[nginx]lua控制响应头
[nginx]lua控制响应头
|
2月前
|
应用服务中间件 API nginx
[nginx]lua控制请求头
[nginx]lua控制请求头
|
5月前
|
负载均衡 应用服务中间件 nginx
解决nginx配置负载均衡时invalid host in upstream报错
在Windows环境下,配置Nginx 1.11.5进行负载均衡时遇到问题,服务无法启动。错误日志显示“invalid host in upstream”。检查发现上游服务器列表中,192.168.29.128的主机地址无效。负载均衡配置中,两个服务器地址前误加了"http://"。修正方法是删除上游服务器列表和proxy_pass中的"http://"。问题解决后,Nginx服务应能正常启动。
337 4
解决nginx配置负载均衡时invalid host in upstream报错
|
11月前
|
负载均衡 Dubbo 应用服务中间件
Nginx系列教程(11) - HTTP动态负载均衡(一)
Nginx系列教程(11) - HTTP动态负载均衡(一)
120 0
|
5月前
|
NoSQL 关系型数据库 应用服务中间件
Linux安装 OpenResty、Nginx、PHP、Mysql、Redis、Lua、Node、Golang、MongoDB、Kafka等
Linux安装 OpenResty、Nginx、PHP、Mysql、Redis、Lua、Node、Golang、MongoDB、Kafka等
160 0
下一篇
无影云桌面