我們構(gòu)建了四層負(fù)載均衡平臺(tái)掸屡,平臺(tái)中四層負(fù)載均衡的服務(wù)是使用LVS擎勘。我們公司使用的linux大多數(shù)的內(nèi)核是4.9.0.XXX冷守,該版本只支持NAT,不能支持fullnat惊科,fullnat是阿里在多年前的2.6.32版本的內(nèi)核上開(kāi)發(fā)支持了fullnat拍摇,并開(kāi)源出來(lái),但是該版本已經(jīng)停止維護(hù)馆截。
目的
LVS缺省只支持NAT充活、Tunnel和DR三種負(fù)載均衡模式蜂莉,由于該版本多年沒(méi)有更新和維護(hù),所以最新的內(nèi)核版本中的LVS原生都是不支持fullnat的混卵。NAT映穗、DR、Tunnel這三種模式都有一定的限制幕随,需要一定的環(huán)境的支持蚁滋,才能正常的工作。
- DR模式的限制:RS跟Director Server必須有一個(gè)網(wǎng)卡在同一個(gè)物理網(wǎng)絡(luò)中
- TUNNEL必須在所有的realserver上綁定VIP
- NAT:RS的網(wǎng)關(guān)必須指向LVS縮在服務(wù)器
目前看起來(lái)只有fullnat是沒(méi)有任何限制的赘淮,而我們正在向業(yè)務(wù)部門推廣容器發(fā)布服務(wù)辕录,在容器中部署的服務(wù),很明顯梢卸,上面三種模式都不可行走诞。為了對(duì)容器中部署的服務(wù)提供LVS的負(fù)載均衡服務(wù),那就必須突破NAT的限制蛤高,支持跨VLAN的fullnat模式呢蚣旱?
基本原理
LVS的NAT服務(wù)提供了DNAT的功能,只要把經(jīng)過(guò)了LVS服務(wù)的包在出LVS主機(jī)的時(shí)候戴陡,再做SNAT處理塞绿,就能夠?qū)崿F(xiàn)fullnat了。
為了實(shí)現(xiàn)這個(gè)目的猜欺,我們可以配合iptables規(guī)則來(lái)實(shí)現(xiàn)通過(guò)LVS的包位隶,在出主機(jī)時(shí),配上對(duì)應(yīng)的SNAT規(guī)則开皿,從而可以實(shí)現(xiàn)了fullnat功能涧黄。
而這種模式也是kube-proxy的實(shí)現(xiàn)的原理,我們的四層負(fù)載均衡平臺(tái)的fullnat也就是參考kube-proxy的細(xì)節(jié)來(lái)實(shí)現(xiàn)的赋荆。
下面我們介紹一下kube-proxy上的ipvs實(shí)現(xiàn)的底層邏輯笋妥,注意這里只會(huì)介紹基于clusterip的實(shí)現(xiàn)細(xì)節(jié),其他都類似窄潭。
kube-proxy中基于clusterip模式的service的負(fù)載均衡細(xì)節(jié)
準(zhǔn)備好一臺(tái)服務(wù)器春宣,假設(shè)服務(wù)器的ip為:10.1.1.1
- 部署好lvs,啟動(dòng)ipvs模塊
# modprobe ip_vs
- 找一臺(tái)服務(wù)應(yīng)用服務(wù)器嫉你,假設(shè)ip為:192.168.1.2月帝,我們?cè)谏厦娌渴鸷胣ginx服務(wù)
端口號(hào)為:8181,nginx.conf的內(nèi)容為:
user www-data;
worker_processes 1;
worker_rlimit_nofile 262140;
error_log logs/error.log;
pid run/nginx.pid;
events
{
use epoll;
worker_connections 65535;
}
http
{
include mime.types;
default_type application/octet-stream;
sendfile on;
aio on;
directio 512;
output_buffers 1 128k;
log_not_found off;
keepalive_timeout 65;
server_tokens off;
gzip on;
gzip_comp_level 6;
gzip_min_length 1k;
gzip_buffers 4 8k;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_types text/plain application/x-javascript text/css application/xml text/javascript application/javascript application/json;
log_format main '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$request_time" "$upstream_response_time"';
access_log logs/${server_name}.access.log main;
fastcgi_intercept_errors on;
error_page 500 502 503 504 /50x.html;
server_names_hash_max_size 4096;
server
{
listen 8181 default;
server_name _;
#access_log off;
location /
{
echo "hello world";
}
}
}
- 啟動(dòng)nginx后幽污,驗(yàn)證nignx正常工作嚷辅。
root@ubuntu:/usr/local/nginx/conf# curl 127.0.0.1:8181
hello world
- 在lvs機(jī)器上創(chuàng)建ipset
ipset create KUBE-CLUSTER-IP hash:ip,port
ipset add KUBE-CLUSTER-IP 10.1.1.1,80
- 在lvs機(jī)器上創(chuàng)建好相應(yīng)的iptables規(guī)則
iptables -N KUBE-SERVICES -t nat
iptables -N KUBE-MARK-MASQ -t nat
iptables -t nat -N KUBE-POSTROUTING
iptables -t nat -I POSTROUTING -m comment --comment "postrouting rule" -j KUBE-POSTROUTING
iptables -t nat -I PREROUTING -m comment --comment "proxy snat" -j LVS_PROXY_CHAIN
iptables -t nat -I KUE-SERVICES -m set --match-set KUBE-CLUSTER-IP dst,dst -j KUBE-MARK-MASQ
iptables -t nat -I KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
iptables -t nat -I KUBE-POSTROUTING -m mark --mark 0x4000/0x4000 -j MASQUERADE
- 在lvs機(jī)器上創(chuàng)建好相應(yīng)的ipvs路由規(guī)則
ipvsadm -A -t 10.1.1.1:80 -s rr
ipvsadm -a -t 10.1.1.1:80 -r 192.168.1.2:8181 -m
- 驗(yàn)證負(fù)載均衡的有效性
curl http://10.1.1.1
hello world
上面的步驟中,我們沒(méi)有在realserver上做任何處理距误,就能夠支持nat簸搞,而且realserver與lvs主機(jī)的ip不在一個(gè)網(wǎng)段中扁位,這樣我們基于LVS實(shí)現(xiàn)了一個(gè)fullnat的負(fù)載均衡功能。
總結(jié)
上面簡(jiǎn)要介紹了kube-proxy中基于ipvs做負(fù)載均衡的實(shí)現(xiàn)的原理和細(xì)節(jié)趁俊,它通過(guò)對(duì)走lvs負(fù)載均衡的包進(jìn)行打好標(biāo)記后域仇,在出主機(jī)訪問(wèn)到realserver時(shí),做snat處理寺擂,從而達(dá)到了fullnat的效果暇务。
最后還要解釋一下,為什么我們不直接用k8s中的service來(lái)對(duì)外提供負(fù)載均衡的服務(wù)呢沽讹?
- 一方面般卑,我們要統(tǒng)一實(shí)現(xiàn)部署在物理機(jī)的服務(wù)的負(fù)載均衡;
- 另一方面爽雄,對(duì)于部署在容器中的服務(wù)ip地址不能對(duì)外蝠检,我們需要把服務(wù)對(duì)外暴漏給業(yè)務(wù)方來(lái)訪問(wèn);
對(duì)于第二點(diǎn)也許有人會(huì)說(shuō)挚瘟,為什么不基于NodePort來(lái)對(duì)外提供服務(wù)呢叹谁,因?yàn)榛贜odePort部署的服務(wù),外面還是需要一個(gè)高可用功能乘盖,那么可能還需要一層LVS來(lái)保證高可用性焰檩。