Imposta nginx in modo che non si blocchi se l'host in upstream non viene trovato


117

Abbiamo diverse app rails sotto un dominio comune in Docker e usiamo nginx per indirizzare le richieste ad app specifiche.

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

La configurazione ha questo aspetto:

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

Se una di queste app non viene avviata, nginx non riesce e si interrompe:

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

Non abbiamo bisogno che siano tutti attivi, ma nginx fallisce altrimenti. Come fare in modo che nginx ignori gli upstream falliti?


1
Stai collegando i contenitori delle app con i contenitori Nginx o li stai eseguendo separatamente l'uno dall'altro? Se l'host all'interno del upstreamblocco non si risolve, in fase di esecuzione, Nginx uscirà con l'errore precedente ...
Justin,

1
Se puoi utilizzare un IP, verrà avviato correttamente. L'utilizzo di resolver( nginx.org/en/docs/http/ngx_http_core_module.html#resolver ) funzionerebbe nel tuo caso?
Justin,

@ Justin abbiamo ogni app in un contenitore separato, anche nginx. Collegali con docker
Morozov

@Justin L'ordine di avvio va bene, nginx si avvia dopo altre app. Vogliamo solo eseguirne solo alcuni :)
Morozov

1
Ho una configurazione simile (contenitore Nginx con contenitore / i di app) . Abbiamo creato un'immagine Nginx che include uno proxy.shscript che legge le variabili di ambiente e aggiunge dinamicamente le upstreamvoci per ciascuna, quindi avvia Nginx. Funziona benissimo in quanto quando eseguiamo il nostro contenitore proxy possiamo passare gli upstream necessari in fase di esecuzione. Potresti fare qualcosa di simile per abilitare / disabilitare determinati upstream all'avvio (o come la mia configurazione aggiungi solo quelli necessari in fase di esecuzione)
Justin

Risposte:


90
  1. Se puoi usare un IP statico, usalo, si avvierà e restituirà solo quello 503se non risponde.

  2. Usa la resolverdirettiva per puntare a qualcosa che può risolvere l'host, indipendentemente dal fatto che sia attualmente attivo o meno.

  3. Risolvilo a locationlivello, se non puoi fare quanto sopra (questo consentirà a Nginx di avviarsi / eseguire) :

    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
la tua opzione 3 funziona alla grande per me. Se non specifico un resolver, sai per quanto tempo nginx memorizzerà nella cache l'IP che risolve?
Riley Lark

14
Grazie! Il solo utilizzo di una variabile sembra impedire a nginx di essere intelligente al riguardo
Blanka

1
Ho scoperto che un gruppo di acquisizione di espressioni regolari mi ha permesso di saltare la variabile:location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
Danny Kirchmeier

2
Come funziona per un proxy TCP? Sembra che non ci sia modo di provare l'opzione 3 per il proxy tcp.
krish7919

1
@Charlie questo tipo di errori in nginx sono quasi sempre legati alla mancanza di ";" firmare alla fine della riga :)
SteveB

18

Per me, l'opzione 3 della risposta di @ Justin / @ duskwuff ha risolto il problema, ma ho dovuto cambiare l'IP del resolver in 127.0.0.11 (server DNS di 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;
}

Ma come menzionato da @ Justin / @ duskwuff, puoi usare qualsiasi altro server DNS esterno.


15

Il vantaggio principale dell'utilizzo upstreamè definire un gruppo di server in grado di ascoltare su porte diverse e configurare il bilanciamento del carico e il failover tra di loro .

Nel tuo caso stai definendo solo 1 server primario per upstream, quindi deve essere attivo .

Invece, usa le variabili per i tuoi proxy_passe ricorda di gestire i possibili errori (404, 503) che potresti ottenere quando un server di destinazione è inattivo.


1
> Utilizza invece le variabili per i tuoi proxy_pass e ricorda di gestire i possibili errori (404, 503) che potresti ottenere quando un server di destinazione è inattivo. Puoi spiegarci come farlo? Se lo faccio set $variable http://fooe proxy_pass $variablee mantengo il foo "a monte" (per mantenere i vantaggi che hai menzionato), allora sto ancora affrontando il problema menzionato da OP.
Tibor Vass

6
Come puoi vedere in altri esempi, sarà set $variable fooeproxy_pass http://$variable
danielgpm

2
@danielgpm Come hai affermato, l'utilizzo della variabile per proxy_pass funziona perfettamente e ha risolto il mio problema. Sarebbe utile per gli altri se
potessi

3
E se ne ho più di uno e desidero ignorare quelli che non possono essere risolti?
talabes

0

Ho riscontrato lo stesso problema "Host non trovato" perché parte del mio host veniva mappata utilizzando $uriinvece di $request_uri:

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

E quando la richiesta è cambiata nella richiesta secondaria di autenticazione, ha $uriperso il suo valore iniziale. La modifica della mappatura da utilizzare $request_uriinvece di $uririsolvere il mio problema:

map $request_uri $kubernetes {
    # ...
}

-8

Non è possibile utilizzare l' --linkopzione, invece è possibile utilizzare la mappatura delle porte e associare nginx all'indirizzo host.

Esempio: esegui il tuo primo contenitore Docker con -p 180:80opzione, il secondo contenitore con -p 280:80opzione.

Esegui nginx e imposta questi indirizzi per il proxy:

proxy_pass http://192.168.1.20:180/; # first container
proxy_pass http://192.168.1.20:280/; # second container
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.