天天看點

使用IPVS實作Kubernetes入口流量負載均衡

新搭建的Kubernetes叢集如何承接外部通路的流量,是剛上手Kubernetes時常常會遇到的問題。 在公有雲上,官方給出了比較直接的答案,使用

LoadBalancer

類型的Service,利用公有雲提供的負載均衡服務來承接流量, 同時在多台伺服器之間進行負載均衡。而在私有環境中,如何正确的将外部流量引入到叢集内部,卻暫時沒有标準的做法。 本文将介紹一種基于IPVS來承接流量并實 現負載均衡的方法,供大家參考。

IPVS

LVS

項目的一部分,是一款運作在Linux kernel當中的4層負載均衡器,性能異常優秀。 根據

這篇文章

的介紹,使用調優後的核心,可以輕松處理每秒10萬次以上的轉發請求。目前在中大型網際網路項目中, IPVS被廣泛的使用,用于承接網站入口處的流量。

Kubernetes Service

Service

是Kubernetes的基礎概念之一,它将一組Pod抽象成為一項服務,統一的對外提供服務,在各個Pod之間實作負載均衡。 Service有多種類型,最基本的

ClusterIP

類型解決了叢集内部通路服務的需求,

NodePort

類型通過Node節點的端口暴露服務, 再配合上

LoadBalancer

類型所定義的負載均衡器,實作了流量經過前端負載均衡器分發到各個Node節點暴露出的端口, 再通過

iptables

進行一次負載均衡,最終分發到實際的Pod上這個過程。

在Service的Spec中,

externalIPs

字段平常鮮有人提到,當把IP位址填入這個字段後,

kube-proxy

會增加對應的

iptables

規則, 當有以對應IP為目标的流量發送到Node節點時,

iptables

将進行NAT,将流量轉發到對應的服務上。一般情況下, 很少會遇到伺服器接受非自身綁定IP流量的情況,是以

externalIPs

不常被使用,但配合網絡層的其他工具,它可以實作給Service綁定外部IP的效果。

今天我們将使用

externalIPs

配合IPVS的DR(Direct Routing)模式實作将外部流量引入到叢集内部,同時實作負載均衡。

環境搭建

為了示範,我們搭建了4台伺服器組成的叢集。一台伺服器運作IPVS,扮演負載均衡器的作用,一台伺服器運作Kubernetes Master元件, 其他兩台伺服器作為Node加入到Kubernetes叢集當中。搭建過程這裡不詳細介紹,大家可以參考相關的文檔。

所有伺服器在

172.17.8.0/24

這個網段中。服務的VIP我們設定為

172.17.8.201

。整體架構入下圖所示:

使用IPVS實作Kubernetes入口流量負載均衡

接下來讓我們來配置IPVS和Kubernetes。

使用externalIPs暴露Kubernetes Service

首先在叢集内部運作2個nginx Pod用作示範。

$ kubectl run nginx --image=nginx --replicas=2      

再将它暴露為Service,同時設定

externalIPs

字段

$ kubectl expose deployment nginx --port 80 --external-ip 172.17.8.201      

檢視

iptables

配置,确認對應的

iptables

規則已經被加入。

$ sudo iptables -t nat -L KUBE-SERVICES -n
Chain KUBE-SERVICES (2 references)
target prot opt source destination
KUBE-SVC-4N57TFCL4MD7ZTDA tcp -- 0.0.0.0/0 10.3.0.156 /* default/nginx: cluster IP */ tcp dpt:80
KUBE-MARK-MASQ tcp -- 0.0.0.0/0 172.17.8.201 /* default/nginx: external IP */ tcp dpt:80
KUBE-SVC-4N57TFCL4MD7ZTDA tcp -- 0.0.0.0/0 172.17.8.201 /* default/nginx: external IP */ tcp dpt:80 PHYSDEV match ! --physdev-is-in ADDRTYPE match src-type !LOCAL
KUBE-SVC-4N57TFCL4MD7ZTDA tcp -- 0.0.0.0/0 172.17.8.201 /* default/nginx: external IP */ tcp dpt:80 ADDRTYPE match dst-type LOCAL
KUBE-SVC-NPX46M4PTMTKRN6Y tcp -- 0.0.0.0/0 10.3.0.1 /* default/kubernetes:https cluster IP */ tcp dpt:443
KUBE-NODEPORTS all -- 0.0.0.0/0 0.0.0.0/0 /* kubernetes service nodeports; NOTE: this must be the last rule in this chain */ ADDRTYPE match dst-type LOCAL      

配置IPVS實作流量轉發

首先在IPVS伺服器上,打開

ipv4_forward

$ sudo sysctl -w net.ipv4.ip_forward=1      

接下來加載IPVS核心子產品。

$ sudo modprobe ip_vs      

将VIP綁定在網卡上。

$ sudo ifconfig eth0:0 172.17.8.201 netmask 255.255.255.0 broadcast 172.17.8.255      

再使用

ipvsadm

來配置IPVS,這裡我們直接使用Docker鏡像,避免和特定發行版綁定。

$ docker run --privileged -it --rm --net host luizbafilho/ipvsadm
/ # ipvsadm
IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn / # ipvsadm -A -t 172.17.8.201:80 / # ipvsadm -a -t 172.17.8.201:80 -r 172.17.8.11:80 -g / # ipvsadm -a -t 172.17.8.201:80 -r 172.17.8.12:80 -g / # ipvsadm
IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 172.17.8.201:http wlc
 -> 172.17.8.11:http Route 1 0 0 -> 172.17.8.12:http Route 1 0 0      

可以看到,我們成功建立了從VIP到後端伺服器的轉發。

驗證轉發效果

首先使用

curl

來測試是否能夠正常通路nginx服務。

$ curl http://172.17.8.201 <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style>
 body {
 width: 35em;
 margin: 0 auto;
 font-family: Tahoma, Verdana, Arial, sans-serif; } </style>
</head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p> <p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body>
</html>      

接下來在

172.17.8.11

上抓包來确認IPVS的工作情況。

$ sudo tcpdump -i any port 80
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on any, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
04:09:07.503858 IP 172.17.8.1.51921 > 172.17.8.201.http: Flags [S], seq 2747628840, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1332071005 ecr 0,sackOK,eol], length 0 04:09:07.504241 IP 10.2.0.1.51921 > 10.2.0.3.http: Flags [S], seq 2747628840, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1332071005 ecr 0,sackOK,eol], length 0 04:09:07.504498 IP 10.2.0.1.51921 > 10.2.0.3.http: Flags [S], seq 2747628840, win 65535, options [mss 1460,nop,wscale 5,nop,nop,TS val 1332071005 ecr 0,sackOK,eol], length 0 04:09:07.504827 IP 10.2.0.3.http > 10.2.0.1.51921: Flags [S.], seq 3762638044, ack 2747628841, win 28960, options [mss 1460,sackOK,TS val 153786592 ecr 1332071005,nop,wscale 7], length 0 04:09:07.504827 IP 10.2.0.3.http > 172.17.8.1.51921: Flags [S.], seq 3762638044, ack 2747628841, win 28960, options [mss 1460,sackOK,TS val 153786592 ecr 1332071005,nop,wscale 7], length 0 04:09:07.504888 IP 172.17.8.201.http > 172.17.8.1.51921: Flags [S.], seq 3762638044, ack 2747628841, win 28960, options [mss 1460,sackOK,TS val 153786592 ecr 1332071005,nop,wscale 7], length 0 04:09:07.505599 IP 172.17.8.1.51921 > 172.17.8.201.http: Flags [.], ack 1, win 4117, options [nop,nop,TS val 1332071007 ecr 153786592], length 0      

可以看到,由用戶端

172.17.8.1

發送給

172.17.8.201

的封包,經過IPVS的中轉發送給了

172.17.8.11

這台伺服器, 并經過NAT後發送給了

10.2.0.3

這個Pod。傳回的封包不經過IPVS伺服器直接從

172.17.8.11

發送給了

172.17.8.1

。 說明IPVS的DR模式工作正常。重複多次測試可以看到流量分别從

172.17.8.11

172.17.8.12

進入,再分發給不同的Pod, 說明負載均衡工作正常。

與傳統的IPVS DR模式配置不同的是,我們并未在承接流量的伺服器上執行綁定VIP,再關閉ARP的操作。 那是因為對VIP的處理直接發生在iptables上,我們無需在伺服器上運作程式來承接流量,iptables會将流量轉發到對應的Pod上。

使用這種方法來承接流量,僅需要配置

externalIPs

為VIP即可,無需對伺服器做任何特殊的設定,使用起來相當友善。

總結

在本文中示範了使用IPVS配合externalIPs實作将外部流量導入到Kubernetes叢集中,并實作負載均衡的方法。 希望可以幫助大家了解IPVS和externalIPs的工作原理,以便在恰當的場景下合理使用這兩項技術解決問題。 實際部署時,還需要考慮背景伺服器可用性檢查,IPVS節點主從備份,水準擴充等問題。在這裡就不詳細介紹了。

在Kubernetes中還有許多與externalIPs類似的非常用功能,有些甚至是使用Annotation來進行配置,将來有機會再進一步分享。

本文轉自中文社群-

使用IPVS實作Kubernetes入口流量負載均衡