如何让Nginx反向代理等待上游上线

问题描述 投票:0回答:2

我有一个监听 UNIX 套接字的服务器应用程序,Nginx 充当反向代理。

现在我希望 Nginx 等到我的应用程序上线,例如我部署更新并重新启动它,没有向客户端返回任何错误。

这是我的 Nginx 配置中的内容:

location / {
#   proxy_pass http://localhost:8080;
    proxy_pass http://unix:/tmp/MyApp.sock;
    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_cache_bypass $http_upgrade;

    proxy_connect_timeout 60;
    proxy_send_timeout 60;
    proxy_read_timeout 60;
}

但是,每当我的应用程序关闭时,Nginx 就会返回

502 Bad Gateway
立即。显然,所有
proxy_*_timeout
设置都没有帮助。

本地 TCP 套接字也会发生同样的情况。使用 UNIX 套接字,当我关闭应用程序时,我确保删除套接字文件,以便 Nginx 可以看到没有应用程序在运行。

我怎样才能告诉它实际上等待一段时间直到套接字变得可用?

nginx nginx-reverse-proxy
2个回答
3
投票

我不认为核心nginx有这样的功能。然而,使用 nginx-lua-module 可以实现类似的效果。即使使用该模块不适合您,我也会在这里发布工作示例,以防对其他人有所帮助。

error_page 502 = @error_502;
location / {
    proxy_pass http://localhost:8080;
    ...
}
location = /heartbeat {
    internal;
    proxy_pass http://localhost:8080;
}
location @error_502 {
    default_type text/plain;
    rewrite_by_lua_block {
        local timeout = 10
        local uri = ngx.var.uri
        local args = ngx.var.args
        local res = { status = 0 }
        while timeout > 0 do
            ngx.sleep(1)
            res = ngx.location.capture("/heartbeat")
            if res.status == 200 then break end
            timeout = timeout - 1
        end
        if res.status == 200 then
            ngx.exec(uri, args)
        end
    }
    content_by_lua_block {
        ngx.status = ngx.HTTP_SERVICE_UNAVAILABLE
        ngx.say("I'd waited too long... exiting.")
        ngx.exit(ngx.OK)
    }
}

或者,要返回标准的 nginx 503 页面,您可以将上面的配置更改为

...
location @error_502 {
    rewrite_by_lua_block {
        ...
        if res.status == 200 then
            ngx.exec(uri, args)
        else
            ngx.exec("@return_503")
        end
    }
}
location @return_503 {
    return 503;
}

这段代码应该非常简单,不需要任何额外的注释。这里使用的

ngx.sleep
是非阻塞的,其参数的粒度为微秒。您的应用程序应该能够处理
/heartbeat
路线才能使用它(可能消耗尽可能少的处理时间)。我确信这也可以适应使用 UNIX 套接字(也许您需要将上游定义移动到单独的
upstream
块)。

重要提示。由于此解决方案依赖于

ngx.location.capture
来发出子请求,因此由于this限制,它与HTTP/2协议不兼容(如果需要,请阅读整个讨论以找出可能的解决方法)。


0
投票

我不会称之为解决方案,但有一种方法可以通过

resolver
来实现这一点。为此,您需要一个 DNS,
docker
将携带一个,但在您的情况下,您需要在您的服务器上自行设置。

server
{
resolver 127.0.0.11 valid=120s; #DNS-IP
resolver_timeout 60; # Timeout for resolver response
}
location / {
  set $upstream_service URI; #URI= DNS-Name:Port
  proxy_pass http://$upstream_service;
}

因此 nginx 无法检查服务的可用性并询问解析器。等待解析器答复直至超时。如果在超时时间内没有应答:502,如果服务在这段时间内返回,它将应答,nginx 将响应 200。

但我不知道它是否可以与袜子一起使用..

© www.soinside.com 2019 - 2024. All rights reserved.