如果找不到上游主机,则安装程序nginx不会崩溃


116

我们在Docker的通用域下有多个Rails应用程序,并且我们使用nginx将请求定向到特定的应用程序。

our_dev_server.com/foo # proxies to foo app
our_dev_server.com/bar # proxies to bar

配置看起来像这样:

upstream foo {
  server foo:3000;
}

upstream bar {
  server bar:3000;
}

# and about 10 more...

server {
  listen *:80 default_server;

  server_name our_dev_server.com;

  location /foo {
      # this is specific to asset management in rails dev
      rewrite ^/foo/assets(/.*)$ /assets/$1 break;
      rewrite ^/foo(/.*)$ /foo/$1 break;
      proxy_pass http://foo;
  }

  location /bar {
      rewrite ^/bar/assets(/.*)$ /assets/$1 break;
      rewrite ^/bar(/.*)$ /bar/$1 break;
      proxy_pass http://bar;
  }

  # and about 10 more...
}

如果这些应用之一未启动,则nginx失败并停止:

host not found in upstream "bar:3000" in /etc/nginx/conf.d/nginx.conf:6

我们不需要全部启动,否则nginx失败。如何使Nginx忽略失败的上游?


1
您是将应用程序容器与Nginx容器链接在一起,还是彼此分开运行它们?如果upstream块内的主机在运行时无法解析,则Nginx将退出并显示上述错误...
Justin

1
如果您可以使用IP,则可以正常启动。在您的情况下,可以使用resolvernginx.org/en/docs/http/ngx_http_core_module.html#resolver)吗?
贾斯汀

@Justin我们将每个应用程序都放在单独的容器中,nginx也是如此。将它们与docker链接
Morozov

@Justin启动顺序很好,nginx在其他应用程序之后启动。我们只想运行其中的一部分:)
Morozov

1
我有一个类似的设置(带有应用程序容器的Nginx容器)。我们创建了一个Nginx图像,其中包含一个proxy.sh读取环境变量并动态添加的脚本upstream为每个项,然后启动Nginx。这非常有用,因为当我们运行代理容器时,我们可以在运行时传递所需的上游。您可以执行类似的操作以在启动时启用/禁用某些上游(或像我的设置一样在运行时添加所需的
Justin

Answers:


90
  1. 如果您可以使用静态IP,则只需使用它,它将启动并在503没有响应的情况下返回。

  2. 使用resolver指令可以指向可以解析主机的对象,无论它当前是否正在运行。

  3. location如果您无法执行上述操作,请在一级解决(这将使Nginx可以启动/运行)

    location /foo {
      resolver 127.0.0.1 valid=30s;
      # or some other DNS (you company/internal DNS server)
      #resolver 8.8.8.8 valid=30s;
      set $upstream_foo foo;
      proxy_pass http://$upstream_foo:80;
    }
    
    location /bar {
      resolver 127.0.0.1 valid=30s;
      # or some other DNS (you company/internal DNS server)
      #resolver 8.8.8.8 valid=30s;
      set $upstream_bar foo;
      proxy_pass http://$upstream_bar:80;
    }
    

1
您的选择3对我来说很棒。如果我未指定解析器,您是否知道nginx将解析的IP缓存多长时间?
Riley Lark

14
谢谢!仅使用变量似乎会使nginx变得不那么聪明
Blanka

1
我发现一个正则表达式捕获组使我可以跳过变量:location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
Danny Kirchmeier

2
这对TCP代理如何起作用?似乎没有办法尝试tcp代理的选项3。
krish7919 '17

1
@Charlie nginx中的这类错误几乎总是与缺少“;”有关 行末签名:)
SteveB,

18

对我来说,@ Justin / @ duskwuff的答案的选项3解决了这个问题,但是我不得不将解析器IP更改为127.0.0.11(Docker的DNS服务器):

location /foo {
  resolver 127.0.0.11 valid=30s;
  set $upstream_foo foo;
  proxy_pass http://$upstream_foo:80;
}

location /bar {
  resolver 127.0.0.11 valid=30s;
  set $upstream_bar foo;
  proxy_pass http://$upstream_bar:80;
}

但是正如@ Justin / @ duskwuff所述,您可以使用任何其他外部DNS服务器。


15

使用的主要优点upstream是定义了一组服务器,它们可以侦听不同的端口在它们之间配置负载平衡和故障转移

在您的情况下,每个上游仅定义1个主服务器,因此必须将其启动

相反,请为您的变量使用变量,proxy_pass并记住处理目标服务器停机时可能出现的错误(404、503)。


1
>相反,对您的proxy_pass使用变量,并记住处理目标服务器停机时可能出现的错误(404、503)。您能详细说明如何做吗?如果我这样做set $variable http://foo并且proxy_pass $variable保留foo的“上游”(以保持您提到的优势),那么我仍然会遇到OP提到的问题。
Tibor Vass

6
正如你可以在其他的例子看,这将是set $variable fooproxy_pass http://$variable
danielgpm

2
@danielgpm如您所述,将变量用于proxy_pass可以完美地解决我的问题。如果您可以更新答案并举例说明,它将对其他人有所帮助
Nitb

3
如果我不止一个,而又想忽略那些无法解决的问题,该怎么办?
talabes

0

我遇到了相同的“找不到主机”问题,因为部分主机是使用$uri而不是来映射的$request_uri

proxy_pass http://one-api-service.$kubernetes:8091/auth;

并且当请求更改为auth子请求时,将$uri丢失其初始值。更改映射以使用$request_uri而不是$uri解决了我的问题:

map $request_uri $kubernetes {
    # ...
}

-8

您不能使用--link选项,而是可以使用端口映射并将nginx绑定到主机地址。

示例:运行带有-p 180:80选项的第一个Docker容器,运行带有选项的第二个容器-p 280:80

运行nginx并为代理设置以下地址:

proxy_pass http://192.168.1.20:180/; # first container
proxy_pass http://192.168.1.20:280/; # second container
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.