Setup nginx agar tidak crash jika host di upstream tidak ditemukan

117

Kami memiliki beberapa aplikasi rel di bawah domain umum di Docker, dan kami menggunakan nginx untuk mengarahkan permintaan ke aplikasi tertentu.

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

Config terlihat seperti ini:

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

Jika salah satu dari aplikasi ini tidak dimulai maka nginx gagal dan berhenti:

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

Kami tidak membutuhkan semuanya untuk aktif tetapi nginx gagal jika tidak. Bagaimana cara membuat nginx mengabaikan upstream yang gagal?

Morozov
sumber
1
Apakah Anda menautkan wadah aplikasi dengan wadah Nginx, atau menjalankannya secara terpisah satu sama lain? Jika host dalam upstreamblok tidak menyelesaikan, saat runtime, maka Nginx akan keluar dengan kesalahan di atas ...
Justin
1
Jika Anda dapat menggunakan IP maka itu akan mulai dengan baik. Apakah menggunakan resolver( nginx.org/en/docs/http/ngx_http_core_module.html#resolver ) akan berhasil dalam kasus Anda?
Justin
@Justin kami memiliki setiap aplikasi dalam wadah terpisah, nginx juga. Tautkan mereka dengan buruh pelabuhan
Morozov
@Justin Urutan Startup baik-baik saja, nginx dimulai setelah aplikasi lain. Kami hanya ingin menjalankan beberapa saja :)
Morozov
1
Saya memiliki pengaturan serupa (wadah Nginx dengan wadah aplikasi) . Kami membuat gambar Nginx yang menyertakan proxy.shskrip yang membaca variabel lingkungan dan secara dinamis menambahkan upstreamentri untuk masing-masing variabel , lalu memulai Nginx. Ini bekerja dengan baik karena ketika kita menjalankan penampung proxy kita, kita dapat meneruskan upstream yang dibutuhkan pada waktu proses. Anda dapat melakukan sesuatu yang serupa untuk mengaktifkan / menonaktifkan hulu tertentu saat peluncuran (atau seperti penyiapan saya, tambahkan saja yang diperlukan saat runtime)
Justin

Jawaban:

90
  1. Jika Anda dapat menggunakan IP statis maka gunakan saja, itu akan startup dan hanya kembali 503jika tidak merespon.

  2. Gunakan resolverarahan untuk menunjuk ke sesuatu yang dapat menyelesaikan masalah tuan rumah, terlepas dari apakah itu saat ini atau tidak.

  3. Selesaikan di locationlevel, jika Anda tidak dapat melakukan hal di atas (ini akan memungkinkan Nginx untuk memulai / menjalankan) :

    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
sumber
1
opsi 3 Anda sangat cocok untuk saya. Jika saya tidak menentukan resolver, apakah Anda tahu berapa lama nginx akan menyimpan cache IP yang diselesaikan?
Riley Lark
14
Terima kasih! Hanya menggunakan variabel tampaknya mencegah nginx menjadi pintar tentangnya
Blanka
1
Saya menemukan bahwa grup penangkap regex memungkinkan saya untuk melewati variabel:location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
Danny Kirchmeier
2
Bagaimana cara kerjanya untuk proxy TCP? Sepertinya tidak ada cara untuk mencoba opsi 3 untuk proxy tcp.
krish7919
1
@Charlie Jenis kesalahan di nginx hampir selalu terkait dengan ";" yang hilang tanda tangan di akhir baris :)
SteveB
18

Bagi saya, opsi 3 dari jawaban dari @ Justin / @ senjawuff menyelesaikan masalah, tetapi saya harus mengubah IP resolver ke 127.0.0.11 (server DNS 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;
}

Namun seperti yang disebutkan @ Justin / @ senjawuff, Anda dapat menggunakan server DNS eksternal lainnya.

neumann
sumber
15

Keuntungan utama penggunaan upstreamadalah untuk menentukan sekelompok server yang dapat mendengarkan pada port yang berbeda dan mengonfigurasi load-balancing dan failover di antara mereka .

Dalam kasus Anda, Anda hanya menentukan 1 server utama per upstream sehingga harus up .

Sebaliknya, gunakan variabel untuk Anda proxy_passdan ingatlah untuk menangani kemungkinan kesalahan (404s, 503s) yang mungkin Anda dapatkan saat server target tidak aktif.

danielgpm
sumber
1
> Sebaliknya, gunakan variabel untuk proxy_pass Anda dan ingatlah untuk menangani kemungkinan kesalahan (404s, 503s) yang mungkin Anda dapatkan saat server target tidak aktif. Bisakah Anda menjelaskan cara melakukannya? Jika saya melakukan set $variable http://foodan proxy_pass $variabledan menjaga foo "upstream" (untuk menjaga keuntungan yang Anda sebutkan) maka saya masih mengenai masalah yang disebutkan oleh OP.
Tibor Vass
6
Seperti yang dapat Anda lihat di contoh lain, itu akan menjadi set $variable foodanproxy_pass http://$variable
danielgpm
2
@danielgpm Seperti yang Anda nyatakan, menggunakan variabel untuk proxy_pass bekerja dengan sempurna dan memecahkan masalah saya. Akan membantu orang lain jika Anda dapat memperbarui jawaban Anda dan menyebutkannya sebagai contoh
Nitb
3
Bagaimana jika saya memiliki lebih dari satu, dan saya ingin mengabaikan yang tidak dapat diselesaikan?
Talabes
0

Saya mengalami masalah "Host tidak ditemukan" yang sama karena bagian dari host saya sedang dipetakan menggunakan, $uribukan $request_uri:

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

Dan ketika permintaan berubah menjadi permintaan auth, nilai $uriawalnya hilang. Mengubah pemetaan untuk digunakan $request_urialih-alih $urimenyelesaikan masalah saya:

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

Anda tidak dapat menggunakan --linkopsi, sebagai gantinya Anda dapat menggunakan pemetaan port dan mengikat nginx ke alamat host.

Contoh: Jalankan kontainer buruh pelabuhan pertama Anda dengan -p 180:80opsi, kontainer kedua dengan -p 280:80opsi.

Jalankan nginx dan atur alamat ini untuk proxy:

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