1. 程式人生 > >使用IPVS實現Kubernetes入口流量負載均衡_Kubernetes中文社群

使用IPVS實現Kubernetes入口流量負載均衡_Kubernetes中文社群

新搭建的Kubernetes叢集如何承接外部訪問的流量,是剛上手Kubernetes時常常會遇到的問題。 在公有云上,官方給出了比較直接的答案,使用LoadBalancer型別的Service,利用公有云提供的負載均衡服務來承接流量, 同時在多臺伺服器之間進行負載均衡。而在私有環境中,如何正確的將外部流量引入到叢集內部,卻暫時沒有標準的做法。 本文將介紹一種基於IPVS來承接流量並實現負載均衡的方法,供大家參考。

IPVS

IPVSLVS專案的一部分,是一款執行在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.11172.17.8.12進入,再分發給不同的Pod, 說明負載均衡工作正常。

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

使用這種方法來承接流量,僅需要配置externalIPs為VIP即可,無需對伺服器做任何特殊的設定,使用起來相當方便。

總結

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

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

最後插播下廣告,為了實現私有環境下的Kubernetes叢集自動化部署和運維,我們為Archon系統增加了PXE管理物理機的支援, 相應的配置案例在這裡。如果使用過程中有任何問題,歡迎跟我們聯絡。