Skonfiguruj nginx tak, aby nie ulegał awarii, jeśli nie zostanie znaleziony host w źródle

117

Mamy kilka aplikacji railsowych w ramach wspólnej domeny w Dockerze i używamy nginx do kierowania żądań do określonych aplikacji.

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

Konfiguracja wygląda tak:

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

Jeśli jedna z tych aplikacji nie zostanie uruchomiona, nginx zawiedzie i zatrzyma się:

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

Nie potrzebujemy ich wszystkich, ale w przeciwnym razie nginx zawodzi. Jak sprawić, by Nginx ignorował nieudane upstreams?

Morozov
źródło
1
Czy łączysz kontenery aplikacji z kontenerami Nginx, czy też uruchamiasz je oddzielnie od siebie? Jeśli host w upstreambloku nie zostanie rozwiązany, w czasie działania Nginx zakończy działanie z powyższym błędem ...
Justin
1
Jeśli możesz użyć adresu IP, uruchomi się poprawnie. Czy użycie resolver( nginx.org/en/docs/http/ngx_http_core_module.html#resolver ) zadziała w Twoim przypadku?
Justin
@Justin mamy każdą aplikację w osobnym kontenerze, również nginx. Połącz je z dockerem
Morozov
@Justin Kolejność startowa jest w porządku, nginx uruchamia się po innych aplikacjach. Chcemy tylko uruchomić tylko niektóre :)
Morozov
1
Mam podobną konfigurację (kontener Nginx z kontenerami aplikacji) . Stworzyliśmy obraz Nginx, który zawiera proxy.shskrypt, który czyta zmienne środowiskowe i dynamicznie dodaje upstreamwpisy dla każdego, a następnie uruchamia Nginx. Działa to świetnie, ponieważ kiedy uruchamiamy nasz kontener proxy, możemy przekazać potrzebne upstremy w czasie wykonywania. Możesz zrobić coś podobnego, aby włączyć / wyłączyć niektóre upstreams podczas uruchamiania (lub, tak jak moja konfiguracja, po prostu dodać te potrzebne w czasie wykonywania)
Justin

Odpowiedzi:

90
  1. Jeśli możesz użyć statycznego adresu IP, po prostu użyj go, uruchomi się i po prostu zwróci 503, jeśli nie odpowie.

  2. Użyj resolverdyrektywy, aby wskazać coś, co może rozwiązać hosta, niezależnie od tego, czy obecnie działa, czy nie.

  3. Rozwiąż to na locationpoziomie, jeśli nie możesz zrobić powyższego (pozwoli to Nginx na uruchomienie / uruchomienie) :

    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
źródło
1
Twoja opcja 3 działa dla mnie świetnie. Jeśli nie podam resolvera, czy wiesz, jak długo nginx będzie buforował rozwiązany adres IP?
Riley Lark
14
Dzięki! Samo użycie zmiennej wydaje się powstrzymywać nginx przed sprytem
Blanka
1
Okazało się, że grupa przechwytywania location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
wyrażeń
2
Jak to działa w przypadku proxy TCP? Wygląda na to, że nie ma możliwości wypróbowania opcji 3 dla serwera proxy TCP.
krish7919
1
@Charlie tego rodzaju błędy w nginx są prawie zawsze związane z brakującym ";" znak na końcu linii :)
SteveB
18

U mnie opcja 3 odpowiedzi od @ Justin / @ duskwuff rozwiązała problem, ale musiałem zmienić adres IP resolwera na 127.0.0.11 (serwer DNS Dockera ):

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

Ale jak wspomniał @ Justin / @ duskwuff, możesz użyć dowolnego innego zewnętrznego serwera DNS.

neumann
źródło
15

Główną zaletą korzystania z programu upstreamjest zdefiniowanie grupy serwerów, które mogą nasłuchiwać na różnych portach i skonfigurować równoważenie obciążenia i przełączanie awaryjne między nimi .

W twoim przypadku definiujesz tylko 1 serwer główny na serwer nadrzędny, więc musi on działać .

Zamiast tego użyj zmiennych dla swoich proxy_passi pamiętaj, aby obsłużyć możliwe błędy (404, 503), które mogą wystąpić, gdy serwer docelowy nie działa.

danielgpm
źródło
1
> Zamiast tego użyj zmiennych dla swoich proxy_pass (y) i pamiętaj, aby obsłużyć możliwe błędy (404s, 503s), które mogą wystąpić, gdy serwer docelowy jest wyłączony. Czy możesz wyjaśnić, jak to zrobić? Jeśli to zrobię set $variable http://fooi proxy_pass $variablezachowam foo "upstream" (aby zachować wspomniane zalety), to nadal napotykam problem wspomniany przez OP.
Tibor Vass
6
Jak widać w innych przykładach, to będzie set $variable fooiproxy_pass http://$variable
danielgpm
2
@danielgpm Jak już wspomniałeś, użycie zmiennej dla proxy_pass działa idealnie i rozwiązało mój problem. Pomogłoby innym, gdybyś zaktualizował swoją odpowiedź i wspomniał o tym jako przykład
Nitb
3
A jeśli mam więcej niż jeden i chcę zignorować te, których nie można rozwiązać?
talabes
0

Miałem to samo „Host not found” problem, ponieważ część mojego hosta był odwzorowany za pomocą $urizamiast $request_uri:

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

A kiedy żądanie zmieniło się w żądanie autoryzacji, $uriutrata wartości początkowej. Zmiana mapowania na użycie $request_urizamiast $urirozwiązania mojego problemu:

map $request_uri $kubernetes {
    # ...
}
Washington Guedes
źródło
-8

Nie możesz użyć --linkopcji, zamiast tego możesz użyć mapowania portów i powiązać nginx z adresem hosta.

Przykład: Uruchom pierwszy kontener docker z -p 180:80opcją, drugi kontener z -p 280:80opcją.

Uruchom nginx i ustaw te adresy dla serwera proxy:

proxy_pass http://192.168.1.20:180/; # first container
proxy_pass http://192.168.1.20:280/; # second container
kvaps
źródło