Configure nginx para que no se bloquee si no se encuentra el host en el flujo ascendente

117

Tenemos varias aplicaciones de rieles bajo un dominio común en Docker, y usamos nginx para dirigir solicitudes a aplicaciones específicas.

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

La configuración se ve así:

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...
}

Si una de estas aplicaciones no se inicia, nginx falla y se detiene:

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

No los necesitamos todos para estar activos, pero nginx falla de lo contrario. ¿Cómo hacer que nginx ignore los upstreams fallidos?

Morozov
fuente
1
¿Está vinculando los contenedores de la aplicación con los contenedores de Nginx o ejecutándolos por separado? Si el host dentro del upstreambloque no se resuelve, en tiempo de ejecución, Nginx saldrá con el error anterior ...
Justin
1
Si puede usar una IP, se iniciará bien. ¿ Usaríaresolver ( nginx.org/en/docs/http/ngx_http_core_module.html#resolver ) en su caso?
Justin
@Justin tenemos cada aplicación en un contenedor separado, nginx también. Conéctelos con Docker
Morozov
@Justin El orden de inicio está bien, nginx comienza después de otras aplicaciones. Solo queremos ejecutar solo algunos de ellos :)
Morozov
1
Tengo una configuración similar (contenedor Nginx con contenedor (s) de aplicaciones) . Creamos una imagen de Nginx que incluye un proxy.shscript que lee variables de entorno y agrega upstreamentradas dinámicamente para cada una, luego inicia Nginx. Esto funciona muy bien porque cuando ejecutamos nuestro contenedor de proxy podemos pasar los flujos ascendentes necesarios en tiempo de ejecución. Puede hacer algo similar para habilitar / deshabilitar ciertas corrientes ascendentes en el lanzamiento (o como mi configuración, simplemente agregue las necesarias en tiempo de ejecución)
Justin

Respuestas:

90
  1. Si puede usar una IP estática, utilícela, se iniciará y devolverá 503la si no responde.

  2. Utilice la resolverdirectiva para señalar algo que pueda resolver el host, independientemente de si está activo o no.

  3. Resuélvalo en el locationnivel, si no puede hacer lo anterior (esto permitirá que Nginx se inicie / ejecute) :

    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;
    }
    
Justin
fuente
1
tu opción 3 funciona muy bien para mí. Si no especifico un resolutor, ¿sabe cuánto tiempo nginx almacenará en caché la IP que resuelve?
Riley Lark
14
¡Gracias! El solo uso de una variable parece evitar que nginx sea inteligente al respecto
Blanka
1
Descubrí que un grupo de captura de location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
expresiones regulares
2
¿Cómo funciona eso para un proxy TCP? Parece que no hay forma de probar la opción 3 para el proxy tcp.
krish7919
1
@Charlie, ese tipo de errores en nginx casi siempre están relacionados con la falta ";" firmar al final de la línea :)
SteveB
18

Para mí, la opción 3 de la respuesta de @ Justin / @ Sunsetwuff resolvió el problema, pero tuve que cambiar la IP del resolutor a 127.0.0.11 (servidor DNS de Docker):

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;
}

Pero como mencionó @ Justin / @ anochecerwuff, podría usar cualquier otro servidor DNS externo.

Neumann
fuente
15

La principal ventaja de usar upstreames definir un grupo de servidores que pueden escuchar en diferentes puertos y configurar el equilibrio de carga y la conmutación por error entre ellos .

En su caso, solo está definiendo 1 servidor primario por flujo ascendente, por lo que debe estar activo .

En su lugar, use variables para su proxy_pass(s) y recuerde manejar los posibles errores (404, 503) que puede obtener cuando un servidor de destino no funciona.

danielgpm
fuente
1
> En su lugar, use variables para su (s) proxy_pass (es) y recuerde manejar los posibles errores (404, 503) que puede obtener cuando un servidor de destino no funciona. ¿Puedes explicarnos cómo hacerlo? Si lo hago set $variable http://fooy proxy_pass $variablemantengo el foo "upstream" (para mantener las ventajas que mencionaste), entonces todavía estaré abordando el problema mencionado por OP.
Tibor Vass
6
Como puede ver en otros ejemplos, será set $variable fooyproxy_pass http://$variable
danielgpm
2
@danielgpm Como dijiste, usar la variable para proxy_pass funciona perfectamente y resolvió mi problema.
Ayudaría a
3
¿Qué pasa si tengo más de uno y quiero ignorar los que no se pueden resolver?
talabes
0

Tuve el mismo problema de "Host no encontrado" porque parte de mi host se estaba mapeando usando en $urilugar de $request_uri:

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

Y cuando la solicitud cambió a la subquest de autenticación, $uriperdió su valor inicial. Cambiar el mapeo para usar en $request_urilugar de $uriresolver mi problema:

map $request_uri $kubernetes {
    # ...
}
Washington Guedes
fuente
-8

No puede usar la --linkopción, en su lugar puede usar la asignación de puertos y vincular nginx a la dirección del host.

Ejemplo: Ejecute su primer contenedor docker con -p 180:80opción, segundo contenedor con -p 280:80opción.

Ejecute nginx y configure estas direcciones para el proxy:

proxy_pass http://192.168.1.20:180/; # first container
proxy_pass http://192.168.1.20:280/; # second container
kvaps
fuente