ตั้งค่า nginx ไม่ให้หยุดทำงานหากไม่พบโฮสต์ในต้นน้ำ


118

เรามีแอพทางรถไฟหลายตัวภายใต้โดเมนทั่วไปใน Docker และเราใช้ nginx เพื่อส่งคำขอไปยังแอพเฉพาะ

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

Config มีลักษณะดังนี้:

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

หากแอปใดแอปหนึ่งเหล่านี้ไม่เริ่มทำงาน nginx จะล้มเหลวและหยุดทำงาน:

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

เราไม่ต้องการให้พวกเขาทั้งหมดขึ้น แต่ nginx ล้มเหลวเป็นอย่างอื่น จะทำให้ nginx ละเว้นต้นน้ำล้มเหลวได้อย่างไร


1
คุณกำลังเชื่อมโยงคอนเทนเนอร์ของแอปกับคอนเทนเนอร์ Nginx หรือเรียกใช้แยกจากกัน หากโฮสต์ภายในupstreamบล็อกไม่สามารถแก้ไขได้เมื่อรันไทม์ Nginx จะออกพร้อมกับข้อผิดพลาดข้างต้น ...
จัสติน

1
หากคุณสามารถใช้ IP ได้ก็จะเริ่มต้นได้ดี การใช้resolver( nginx.org/en/docs/http/ngx_http_core_module.html#resolver ) จะใช้ได้ผลไหมในกรณีของคุณ
จัสติน

@ จัสตินเรามีแต่ละแอพในคอนเทนเนอร์แยกต่างหาก nginx ด้วย เชื่อมโยงกับนักเทียบท่า
Morozov

@Justin คำสั่งเริ่มต้นใช้ได้ดี nginx เริ่มต้นหลังจากแอปอื่น ๆ เราต้องการเรียกใช้เฉพาะบางส่วนเท่านั้น :)
Morozov

1
ฉันมีการตั้งค่าที่คล้ายกัน(Nginx ภาชนะที่มีภาชนะแอป (s)) เราสร้างอิมเมจ Nginx ที่มีproxy.shสคริปต์ที่อ่านตัวแปรสภาพแวดล้อมและเพิ่มupstreamรายการแบบไดนามิกสำหรับแต่ละรายการจากนั้นเริ่ม Nginx สิ่งนี้ใช้งานได้ดีเมื่อเราเรียกใช้พร็อกซีคอนเทนเนอร์ของเราเราสามารถส่งผ่านอัปสตรีมที่จำเป็นในรันไทม์ได้ คุณสามารถทำสิ่งที่คล้ายกับการเปิด / ปิดการใช้งานอัปสตรีมบางอย่างเมื่อเปิดตัว(หรือเช่นเดียวกับการตั้งค่าของฉันเพียงแค่เพิ่มสิ่งที่จำเป็นในรันไทม์)
Justin

คำตอบ:


90
  1. หากคุณสามารถใช้ IP แบบคงที่ได้ก็ใช้เพียงแค่นั้น IP นั้นจะเริ่มทำงานและจะส่งคืน503หากไม่ตอบสนอง

  2. ใช้resolverคำสั่งเพื่อชี้ไปที่สิ่งที่สามารถแก้ไขโฮสต์ได้ไม่ว่าจะเป็นปัจจุบันหรือไม่ก็ตาม

  3. แก้ไขในlocationระดับหากคุณไม่สามารถทำตามข้างบนได้(สิ่งนี้จะทำให้ Nginx เริ่ม / รัน) :

    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
ตัวเลือก 3 ของคุณใช้งานได้ดีสำหรับฉัน ถ้าฉันไม่ระบุตัวแก้ไขคุณรู้ไหมว่า nginx จะแคช IP ที่แก้ไขได้นานแค่ไหน?
Riley Lark

14
ขอบคุณ! เพียงแค่ใช้ตัวแปรดูเหมือนจะป้องกันไม่ให้ nginx ฉลาดเกี่ยวกับเรื่องนี้
Blanka

1
ฉันพบว่ากลุ่มจับ regex อนุญาตให้ฉันข้ามตัวแปร:location ~ ^/foo/(.*)$ { proxy_pass http://foo/$1; }
Danny Kirchmeier

2
มันทำงานอย่างไรสำหรับพร็อกซี TCP ดูเหมือนจะไม่มีวิธีลองตัวเลือก 3 สำหรับ tcp proxy
krish7919

1
@ ชาร์ลีข้อผิดพลาดประเภทนั้นใน nginx มักเกี่ยวข้องกับการหายไป ";" ลงชื่อท้ายบรรทัด :)
SteveB

18

สำหรับฉันตัวเลือกที่ 3 ของคำตอบจาก @ Justin / @duskwuff แก้ปัญหาได้ แต่ฉันต้องเปลี่ยน IP ตัวแก้ไขเป็น127.0.0.11 (เซิร์ฟเวอร์ 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;
}

แต่ตามที่ @ Justin / @ Duskwuff กล่าวไว้คุณสามารถใช้เซิร์ฟเวอร์ DNS ภายนอกอื่น ๆ


15

ข้อได้เปรียบหลักของการใช้upstreamคือการกำหนดกลุ่มของเซิร์ฟเวอร์ที่สามารถรับฟังได้จากพอร์ตต่างๆและกำหนดค่าการโหลดบาลานซ์และเฟลโอเวอร์ระหว่างกัน

ในกรณีของคุณคุณกำหนดเซิร์ฟเวอร์หลักเพียง 1 เซิร์ฟเวอร์ต่อต้นน้ำดังนั้นจึงต้องอัปเดต

ให้ใช้ตัวแปรสำหรับproxy_pass(es) ของคุณแทนและอย่าลืมจัดการข้อผิดพลาดที่อาจเกิดขึ้น (404s, 503s) ที่คุณอาจได้รับเมื่อเซิร์ฟเวอร์เป้าหมายหยุดทำงาน


1
> ให้ใช้ตัวแปรสำหรับ proxy_pass (es) ของคุณแทนและอย่าลืมจัดการข้อผิดพลาดที่อาจเกิดขึ้น (404s, 503s) ที่คุณอาจได้รับเมื่อเซิร์ฟเวอร์เป้าหมายหยุดทำงาน คุณสามารถอธิบายวิธีการทำอย่างละเอียดได้หรือไม่? ถ้าฉันทำset $variable http://fooและproxy_pass $variableรักษา foo "ต้นน้ำ" ไว้ (เพื่อรักษาข้อดีที่คุณกล่าวถึง) ฉันก็ยังคงกดปุ่มปัญหาที่ OP กล่าวถึง
Tibor Vass

6
ดังที่คุณเห็นในตัวอย่างอื่น ๆ จะเป็นset $variable fooและproxy_pass http://$variable
danielgpm

2
@danielgpm ตามที่คุณระบุการใช้ตัวแปรสำหรับ proxy_pass ทำงานได้อย่างสมบูรณ์และแก้ไขปัญหาของฉันได้ มันจะช่วยคนอื่นได้ถ้าคุณสามารถอัปเดตคำตอบของคุณและพูดถึงสิ่งนั้นเป็นตัวอย่าง
Nitb

3
จะเกิดอะไรขึ้นถ้าฉันมีมากกว่าหนึ่งและฉันต้องการละเว้นสิ่งที่ไม่สามารถแก้ไขได้?
Talabes

0

ฉันมีเดียวกัน "โฮสต์ไม่พบ" ปัญหาเพราะส่วนหนึ่งของโฮสต์ของฉันถูกแมปโดยใช้$uriแทน$request_uri:

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

และเมื่อคำขอเปลี่ยนเป็นคำขอย่อย auth $uriค่าเริ่มต้นจะหายไป การเปลี่ยนการแมปเพื่อใช้$request_uriแทนการ$uriแก้ไขปัญหาของฉัน:

map $request_uri $kubernetes {
    # ...
}

-8

คุณไม่สามารถใช้--linkตัวเลือกได้ แต่คุณสามารถใช้การแมปพอร์ตและผูก nginx กับที่อยู่โฮสต์ได้

ตัวอย่าง: เรียกใช้คอนเทนเนอร์นักเทียบท่าแรกของคุณด้วย-p 180:80ตัวเลือกคอนเทนเนอร์ที่สองพร้อม-p 280:80ตัวเลือก

เรียกใช้ nginx และตั้งค่าที่อยู่เหล่านี้สำหรับพรอกซี:

proxy_pass http://192.168.1.20:180/; # first container
proxy_pass http://192.168.1.20:280/; # second container
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.