最近在做一個(gè)需求開發(fā):根據(jù)請(qǐng)求后的不同,nginx將請(qǐng)求分發(fā)到不同的后端服務(wù);需要修改kubernetes的ingress-nginx-controller的源碼,調(diào)試的時(shí)候遇到了挺多問題,寫出來,有需要的老鐵可以參考。具體方案就不說了,只說一下nginx配置這一塊。
首先貼出組件版本:
ingress-nginx-controller的版本為0.9-beta.18,可以在github上找到開源的項(xiàng)目源碼:
nginx map配置根據(jù)請(qǐng)求頭不同分配流量到不同后端服務(wù)
nginx版本為:nginx version: nginx/1.13.7
map配置的一個(gè)報(bào)錯(cuò):
nginx.conf文件部分如下:
http {
include /etc/nginx/conf.d/server-map.d/*-map.conf;
include /etc/nginx/conf.d/*-upstream.conf;
include /etc/nginx/conf.d/server-map.d/*-server.conf;
....
map_hash_bucket_size 64;
....
}
在/etc/nginx/conf.d/server-map.d/目錄下的flow-ppp-map.conf:
map $http_x_group_env $svc_upstream {
default zxl-test-splitflow-old-version;
~*old zxl-test-splitflow-old-version;
~*new zxl-test-splitflow-new-version;
}
flow-ppp-server.conf
server {
listen 8998;
server_name aa.hc.harmonycloud.cn;
location /testdemo/test {
proxy_pass http://$svc_upstream;
}
}
ingressgroup-upstream.conf
upstream zxl-test-splitflow-old-version {
server 10.168.173.29:8080 max_fails=0 fail_timeout=0;
}
upstream zxl-test-splitflow-new-version {
server 10.168.177.171:8080 max_fails=0 fail_timeout=0;
}
當(dāng)nginx -tc /etc/nginx/nginx.conf測試配置正確與否時(shí)報(bào)錯(cuò)如下:
Error: exit status 1
nginx: [emerg] "map_hash_bucket_size" directive is duplicate in /etc/nginx/nginx.conf:60
nginx: configuration file c test failed

解決:
這是因?yàn)槭状握{(diào)用map時(shí)會(huì)隱式設(shè)置map_hash_bucket_size,即在nginx中map后寫map_hash_bucket_size相當(dāng)于設(shè)置了兩次map_hash_bucket_size,如:
http {
...
map $status $_status {
default 42;
}
map_hash_bucket_size 64;
...
}
因此可以在map之前設(shè)置它,如下所示。
http {
map_hash_bucket_size 64;
...
map $status $_status {
default 42;
}
...
}
所以include map配置也應(yīng)該放到設(shè)置map_hash_bucket_size之后:
http {
...
map_hash_bucket_size 64;
...
include /etc/nginx/conf.d/server-map.d/*-map.conf;
include /etc/nginx/conf.d/*-upstream.conf;
include /etc/nginx/conf.d/server-map.d/*-server.conf;
}
map配置說明:
通過上面的include三個(gè)配置文件,最終對(duì)nginx生效的配置應(yīng)該是這樣的:
http {
...
map_hash_bucket_size 64;
...
map $http_x_group_env $svc_upstream {
default zxl-test-splitflow-old-version;
~*old zxl-test-splitflow-old-version;
~*new zxl-test-splitflow-new-version;
}
upstream zxl-test-splitflow-old-version {
server 10.168.173.29:8080 max_fails=0 fail_timeout=0;
}
upstream zxl-test-splitflow-new-version {
server 10.168.177.171:8080 max_fails=0 fail_timeout=0;
}
server {
listen 8998;
server_name aa.hc.harmonycloud.cn;
location /testdemo/test {
proxy_pass http://$svc_upstream;
}
}
}
當(dāng)在電腦上hosts文件里配置了aa.hc.harmonycloud.cn域名解析后,訪問http://aa.hc.harmonycloud.cn:8998/testdemo/test時(shí)(即server的server_name和listen、location的配置),nginx將會(huì)把請(qǐng)求轉(zhuǎn)發(fā)到http://$svc_upstream,這個(gè)$svc_upstream具體是什么,就是通過map配置來賦值的。這里map配置如下:
map $http_x_group_env $svc_upstream {
default zxl-test-splitflow-old-version;
~*old zxl-test-splitflow-old-version;
~*new zxl-test-splitflow-new-version;
}
其中$http_x_group_env可以是nginx內(nèi)置變量,也可以是自定義的header的key、請(qǐng)求參數(shù)名;$svc_upstream即為自定義變量名。這里的配置含義為:當(dāng)請(qǐng)求頭里的x-group-env的值old時(shí),$svc_upstream被賦值為zxl-test-splitflow-old-version;當(dāng)請(qǐng)求頭里的x-group-env的值new時(shí),$svc_upstream被賦值為zxl-test-splitflow-new-version;默認(rèn)賦值為zxl-test-splitflow-old-version;
(其中正則表達(dá)式如果以 “~” 開頭,表示這個(gè)正則表達(dá)式對(duì)大小寫敏感。以 “~*”開頭,表示這個(gè)正則表達(dá)式對(duì)大小寫不敏感)。而zxl-test-splitflow-new-version和zxl-test-splitflow-old-version表示兩個(gè)upstream名稱。
因此nginx將會(huì)把請(qǐng)求轉(zhuǎn)發(fā)到http://$svc_upstream,這里的$svc_upstream會(huì)被替換為upstream的名稱,最終將得到upstream中的后端服務(wù)IP和Port。
注意:如果我們自定義header為X-Real-IP,通過第二個(gè)nginx獲取該header時(shí)需要這樣:$http_x_real_ip; (一律采用小寫,而且前面多了個(gè)http_,且中間用_替換)
測試
當(dāng)請(qǐng)求頭里加x-group-env為new時(shí),訪問后端打印出的是I am new version

當(dāng)請(qǐng)求頭里加x-group-env為old時(shí),訪問后端打印出的是I am old version

最終通過請(qǐng)求頭不同實(shí)現(xiàn)了將流量分配到不同的后端服務(wù)。
將請(qǐng)求頭的key變?yōu)閄-Group-Env,value變?yōu)镺LD或者NEW也沒關(guān)系:

