Richten Sie nginx so ein, dass es nicht abstürzt, wenn der Host im Upstream nicht gefunden wird

114

Wir haben mehrere Rails-Apps unter einer gemeinsamen Domäne in Docker und verwenden Nginx, um Anfragen an bestimmte Apps zu leiten.

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

Die Konfiguration sieht folgendermaßen aus:

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

Wenn eine dieser Apps nicht gestartet wird, schlägt nginx fehl und stoppt:

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

Wir brauchen nicht alle, um auf zu sein, aber Nginx schlägt sonst fehl. Wie kann man Nginx dazu bringen, fehlgeschlagene Upstreams zu ignorieren?

Morozov
quelle
1
Verknüpfen Sie die App-Container mit den Nginx-Containern oder führen Sie sie getrennt voneinander aus? Wenn der Host innerhalb des upstreamBlocks zur Laufzeit nicht aufgelöst wird, wird Nginx mit dem obigen Fehler beendet ...
Justin
1
Wenn Sie eine IP verwenden können, wird sie problemlos gestartet. Würde die Verwendung von resolver( nginx.org/en/docs/http/ngx_http_core_module.html#resolver ) in Ihrem Fall funktionieren?
Justin
@ Justin wir haben jede App in einem separaten Container, auch Nginx.
Morozov
@Justin Startreihenfolge ist in Ordnung, Nginx startet nach anderen Apps. Wir wollen nur einige von ihnen laufen lassen :)
Morozov
1
Ich habe ein ähnliches Setup (Nginx-Container mit App-Containern) . Wir haben ein Nginx-Image erstellt, das ein proxy.shSkript enthält, das Umgebungsvariablen liest und upstreamfür jedes dynamisch Einträge hinzufügt . Anschließend wird Nginx gestartet. Dies funktioniert insofern hervorragend, als wir beim Ausführen unseres Proxy-Containers zur Laufzeit die erforderlichen Upstreams übergeben können. Sie könnten etwas Ähnliches tun, um bestimmte Upstreams beim Start zu aktivieren / deaktivieren (oder wie mein Setup nur die zur Laufzeit benötigten hinzufügen)
Justin

Antworten:

90
  1. Wenn Sie eine statische IP verwenden können, verwenden Sie diese einfach. Sie wird gestartet und gibt nur dann zurück 503, wenn sie nicht antwortet.

  2. Verwenden Sie die resolverAnweisung, um auf etwas zu verweisen, das den Host auflösen kann, unabhängig davon, ob er gerade aktiv ist oder nicht.

  3. Löse es auf der locationEbene, wenn du das oben genannte nicht kannst (dies ermöglicht es Nginx zu starten / laufen zu lassen) :

    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
quelle
1
Ihre Option 3 funktioniert gut für mich. Wenn ich keinen Resolver spezifiziere, wissen Sie, wie lange Nginx die aufgelöste IP-Adresse zwischenspeichert?
Riley Lark
14
Vielen Dank! Nur die Verwendung einer Variablen scheint Nginx davon abzuhalten, klug zu sein
Blanka
1
Ich fand, dass eine Regex-Capture-Gruppe mir erlaubte, die Variable zu überspringen:location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
Danny Kirchmeier
2
Wie funktioniert das für einen TCP-Proxy? Anscheinend gibt es keine Möglichkeit, Option 3 für TCP-Proxy auszuprobieren.
krish7919
1
@Charlie diese Art von Fehlern in Nginx hängen fast immer mit fehlenden ";" Zeichen am Ende der Zeile :)
SteveB
17

Für mich löste Option 3 der Antwort von @ Justin / @ duskwuff das Problem, aber ich musste die Resolver-IP auf ändern 127.0.0.11 (Docker-DNS-Server) :

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

Aber wie @ Justin / @ duskwuff erwähnt, können Sie jeden anderen externen DNS-Server verwenden.

neumann
quelle
14

Der Hauptvorteil der Verwendung upstreambesteht darin, eine Gruppe von Servern zu definieren, die verschiedene Ports überwachen und den Lastenausgleich und das Failover zwischen ihnen konfigurieren können .

In Ihrem Fall definieren Sie nur 1 Primärserver pro Upstream, sodass dieser aktiv sein muss .

Verwenden Sie stattdessen Variablen für Ihre proxy_pass(n) und denken Sie daran, die möglichen Fehler (404s, 503s) zu behandeln, die auftreten können, wenn ein Zielserver ausfällt.

danielgpm
quelle
1
> Verwenden Sie stattdessen Variablen für Ihre proxy_pass (s) und denken Sie daran, die möglichen Fehler (404s, 503s) zu behandeln, die auftreten können, wenn ein Zielserver ausfällt. Können Sie näher erläutern, wie das geht? Wenn ich das foo "upstream" mache set $variable http://foound proxy_pass $variablehalte (um die von Ihnen erwähnten Vorteile zu erhalten), treffe ich immer noch das von OP erwähnte Problem.
Tibor Vass
5
Wie Sie in anderen Beispielen sehen können, wird es sein set $variable foo undproxy_pass http://$variable
danielgpm
2
@danielgpm Wie Sie sagten, funktioniert die Verwendung der Variablen für proxy_pass perfekt und hat mein Problem gelöst. Es würde anderen helfen, wenn Sie Ihre Antwort aktualisieren und dies als Beispiel nennen können
Nitb
3
Was ist, wenn ich mehr als eine habe und diejenigen ignorieren möchte, die nicht gelöst werden können?
Talabes
0

Ich hatte das gleiche Problem "Host nicht gefunden", da ein Teil meines Hosts mithilfe $urivon $request_uri:

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

Und als die Anforderung in die Auth-Unteranforderung geändert wurde, $uriverlor die ihren Anfangswert. Das Ändern des zu verwendenden Mappings $request_urianstelle $urimeines Problems hat mein Problem gelöst:

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

Sie können nicht verwenden --link Option , stattdessen können Sie die Portzuordnung verwenden und nginx an die Hostadresse binden.

Beispiel: Führen Sie Ihren ersten Docker-Container mit -p 180:80Option und den zweiten Container mit aus-p 280:80 Option aus.

Führen Sie nginx aus und legen Sie diese Adressen für den Proxy fest:

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