1. 程式人生 > >使用nginx的ngx_upstream_jdomain模塊實現k8s容器的負載均衡

使用nginx的ngx_upstream_jdomain模塊實現k8s容器的負載均衡

提高 max 部署 負載均衡 後來 span spa dir out

使用背景
最近一直在準備k8s上線事宜,目前已經在測試環境中全面部署並通過壓力測試環境檢驗。離正式上線基本只剩下時間問題。我們目前測試環境中的容器負載均衡大量使用到了nginx,就是借助了ngx_upstream_jdomain模塊,從而放棄了k8s官方的ingress。

在這裏簡單說下k8s的ingress。k8s官方的ingress controller其實也是通過nginx來實現的,但是Ingress本身依賴於service,它通過查詢service的映射,來找到service後端的pod的真實ip,並將其掛載到ingress controll的upstream中來實現負載均衡。這本身其實並沒有什麽問題。但由於在我們的k8s中,鑒於標準service基於kube-proxy的轉發效率不高,我們放棄了標準service。轉而直接采用了headless service的方式。這種方式的好處是,dns解析會直接解析到每個pod的ip,而不再解析到service ip,也不再需要kube-proxy來實現轉發。缺點是負載均衡只能依賴dns輪循,沒有靈活的調度策略,但毫無疑問,由於去除了kube-proxy這個中間層,轉發效率得到了提高。另外,由於我們直接打通了Pod與物理服務器之間的網絡,物理網絡中的主機可以與Pod之間通信,如果在中間采用標準的service,service的ip反而無法與物理網絡直接實現通信。

這樣一來,我們外部的負載均衡就沒辦法再去依賴Ingress了,我們采用了在外部部署nginx來實現負載均衡的方法,由於upstream裏的pod ip會動態變化,所以我們不能直接在upstream裏寫死pod的ip地址,而只能用service的域名來替代,並讓nginx自己去解析這個域名,我們知道headless service的域名由於沒有內部的service ip,所以是直接解析到pod ip上的,這樣就等於動態拿到了pod ip。在這種情況下,nginx_upstream_jdomain模塊就登場了。


配置

在具體的配置之前,還得說下,nginx_upstream_jdomain這個模塊嚴重依賴dns解析,另外由於其代理的後端的upstream中的pod ip經常性發生變化,所以dns緩存時間還不能太長。這是一個大坑,在初次配置的時候,以默認值配置resolver,結果我後端pod ip發生變更以後,發現nginx死活還是代理到之前的ip地址,後來一查才發現,默認resolver緩存5分鐘,在傳統應用中,這個緩存時間甚至可以調的更長,但在docker應用中,這個值需要盡可能的短。


ngx_upstream_jdomain的詳細配置可以參考這裏:https://www.nginx.com/resources/wiki/modules/domain_resolve/

我這裏就給出一個示例配置:

resolver 192.168.1.1 valid=1s;
resolver_timeout 3s;
upstream www-stress-80 {
  jdomain www-stress.default.svc.wh01 port=80;
}

server {
  server_name www.stress.test.com;
  listen 80;
  #set $proxy_upstream_name 
"-";   location / {     #Proxy Settings     proxy_redirect off;     proxy_set_header Host $host;     proxy_set_header X-Real-IP $remote_addr;     proxy_set_header CDN-SRC-IP $proxy_add_x_forwarded_for;     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;     proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;     proxy_max_temp_file_size 0;     proxy_connect_timeout 30;     proxy_send_timeout 90;     proxy_read_timeout 90;     proxy_buffer_size 4k;     proxy_buffers 4 32k;     proxy_busy_buffers_size 64k;     proxy_temp_file_write_size 64k;     proxy_pass http://www-stress-80;   } }

另外,還需要說明的是,通過這種方式代理到後端的服務,後端服務接收到的$host的值即為www-stress-80,如果後端服務以主機頭的方式來接受服務,這顯然是不能接受的。所以在代理配置中,必須加上如下配置以將主機頭傳遞給後端服務器:

proxy_set_header Host $host;




使用nginx的ngx_upstream_jdomain模塊實現k8s容器的負載均衡