大綱
- Kubernetes的Service機制
- Iptables實現Service負載均衡
- 當前Iptables實現存在的問題
- IPVS實現Service負載均衡
- Iptables VS. IPVS
Kubernetes的Service機制
但,簡單的生活總是暫時的:
- - 多個後端實例,如何做到負載均衡?
- - 如何保持會話親和性?
- - 容器遷移, IP發生變化如何訪問?
- - 健康檢查怎麼做?
- - 怎麼通過域名訪問?
Iptables實現Service負載均衡
用戶空間應用程序,通過配置Netfilter規則表( Xtables )來構建linux內核防火牆。
Iptables實現流量轉發與負載均衡
Iptables如何做流量轉發?
- DNAT實現IP地址和端口映射
- iptables -t nat -A PREROUTING -d 1.2.3.4/32 --dport 80 -j DNAT --to-destination 10.20.30.40:8080
Iptables如何做負載均衡?
- statistic模塊爲每個後端設置權重
- iptables -t nat -A PREROUTING -d 1.2.3.4 --dport 80 -m statistic --mode random --probability .25 -j DNAT --to-destination 10.20.30.40:8080
Iptables如何做會話保持?
- recent模塊設置會話保持時間
- iptables -t nat –A FOO -m recent --rcheck --seconds 3600 --reap --name BAR -j BAR
當前Iptables實現存在的問題
Iptables做負載均衡的問題
規則線性匹配時延
- - KUBE-SERVICES鏈掛了一長串KUBE-SVC-*鏈;訪問每個service,要遍歷每條鏈直到匹配,時間複雜度O(N)
規則更新時延
- - 非增量式
可擴展性
- - 當系統存在大量iptables規則鏈時,增加/刪除規則會出現kernel lock
- kernel lock: Another app is currently holding the xtables lock. Perhaps you want to use the -w option?
可用性
- - 後端實例擴容,服務會話保持時間更新等都會導致連接斷開
更新Iptables規則的時延
時延出現在哪?
- - 非增量式,即使加上—no-flush(iptables-restore)選項
- - Kube-proxy定期同步iptables狀態:
- * 拷貝所有規則: iptables-save
- * 在內存中更新規則
- * 在內核中修改規則: iptables-restore
- * 規則更新期間存在kernel lock
5K service( 40K 規則),增加一條iptables規則,耗時11min
20K service( 160K 規則),增加一條iptables規則,耗時5h
K8S Scalability
- 5K Nodes, 100K Pod
- 1K Services ??
IPVS實現Service負載均衡
什麼是IPVS( IP Virtual Server)
Linux內核實現的L4 LB, LVS負載均衡的實現
基於netfilter, hash table
支持TCP, UDP, SCTP協議, IPV4, IPV6
支持多種負載均衡策略
- - rr, wrr, lc, wlc, sh, dh, lblc…
支持會話保持
- - persistent connection調度算法
IPVS三種轉發模式
支持三種LB模式: Direct Routing(DR), Tunneling, NAT
- - DR模式工作在L2,最快,但不支持端口映射
- - Tunneling模式用IP包封裝IP包,也稱IPIP模式,不支持端口映射
- - DR和Tunneling模式,回程報文不會經過IPVS Director
- - NAT模式支持端口映射,回程報文經過IPVS Director
- * 內核原生版本只做DNAT,不做SNAT
IPVS工作流
IPVS做L4轉發
1. 綁定VIP
- - dummy網卡
- # ip link add dev dummy0 type dummy
- # ip addr add 192.168.2.2/32 dev dummy0
- - 本地路由表
- # ip route add to local 192.168.2.2/32 dev eth0 proto kernel
- - 網卡別名
- # ifconfig eth0:1 192.168.2.2 netmask 255.255.255.255 up
2. 創建IPVS Virtual Server
- # ipvsadm -A -t 192.168.60.200:80 -s rr -p 600
3. 創建IPVS Real Server
- # ipvsadm -a -t 192.168.60.200:80 -r 172.17.1.2:80 –m
- # ipvsadm -a -t 192.168.60.200:80 -r 172.17.2.3:80 –m
Kubernetes支持IPVS模式
社區1.8 Alpha特性, Owner @m1093782566
社區1.9進beta, Owner @m1093782566
社區1.11進GA,廣泛使用下一步成爲默認模式
支持ClusterIP, NodePort, External IP, Load Balancer…類型Service
- – iptables模式的特性, IPVS模式都支持!
兼容Network Policy
依賴iptables做SNAT和訪問控制
Iptables VS. IPVS
Iptables VS. IPVS 規則刷新時延
Service基數 | 1 | 5000 | 20000 |
Rules基數 | 8 | 40000 | 160000 |
增加1條Iptables規則 | 50 us | 11 min | 5 hours |
增加1條IPVS規則 | 30 us | 50 us | 70 us |
觀察結果:
- 增加一條Iptables的時延,隨着規則數的增加“指數”上升
- 增加一條IPVS的時延,規則基數對其幾乎沒影響
Iptables VS. IPVS 網絡帶寬
Service基數 | 1 | 5000 | 20000 |
Rules基數 | 8 | 40000 | 160000 |
增加1條Iptables規則 | 50 us | 11 min | 5 hours |
增加1條IPVS規則 | 30 us | 50 us | 70 us |
觀察結果:
- 增加一條Iptables的時延,隨着規則數的增加“指數”上升
- 增加一條IPVS的時延,規則基數對其幾乎沒影響
Iptables VS. IPVS 資源消耗
消耗資源 | Service數量 | IPVS | Iptables |
內存 | 1000 | 386 MB | 1.1 G |
5000 | N/A | 1.9 G | |
10000 | 542 MB | 2.3 G | |
15000 | N/A | OOM | |
50000 | 1272 MB | OOM | |
CPU | 1000 | 0% | N/A |
5000 | 50% - 85% | ||
10000 | 50%-100% | ||
15000 | N/A | ||
50000 | N/A |
Iptables VS. IPVS TPS與時延
Iptables
- 靈活,功能強大
- 在prerouting, postrouting, forward, input, output不同階段都能對包進行操作
IPVS
- 更好的性能(hash vs. chain)
- 更多的負載均衡算法
- - rr, wrr, lc, wlc, ip hash…
- 連接保持
- - IPVS service更新期間,保持連接不斷開
- 預先加載內核模
- - nf_conntrack_ipv4, ip_vs, ip_vs_rr, ip_vs_wrr, ipvs_sh…
- # echo 1 > /proc/sys/net/ipv4/vs/conntrack
爲什麼還需要Iptables
因爲我們訪問了一層Service IP!
Node IP -> Service IP( Gateway) -> C客戶端:( Node IP, Service IP), 期望:( Service IP, Node IP)
但實際,經過IPVS一層轉發,包地址變成了( Node IP, C)服務端發出:( C, Node IP) 這個包的源/目的地址與客戶端期望的不一樣! 故將被丟棄
因此,需要一次SNAT( masquerade)!!
( Node IP, Service IP) -> ( IPVS director IP, C)
這也是爲什麼IPVS NAT模式要求回程報文必須經過director!
提問:爲什麼Container A -> Cluster IP -> Container B?
IPSet - 把O(N)的iptables規則降爲O(1)
但,不想要太多iptables…
ipset create KUBE-LOOP-BACK hash:ip,port,ip
ipset add KUBE-LOOP-BACK 192.168.1.1,udp:53,192.168.1.1
ipset add KUBE-LOOP-BACK 192.168.1.2,tcp:80,192.168.1.2
iptables -t nat -A POSTROUTING -m set --match-set KUBE-LOOP-BACK dst,dst,src -j MASQUERADEOUTING O(1)ipset支持“增量”式增/刪/改,而非iptables式全量更新