閱讀956 返回首頁    go 技術社區[雲棲]


使用IPVS實現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。整體架構如下圖所示:

lvs_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 https://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="https://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="https://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管理物理機的支持,相應的配置案例在這裏。如果使用過程中有任何問題,歡迎跟我們聯係。

最後更新:2017-05-15 22:01:34

  上一篇:go  後台開發:核心技術與應用實踐1.1 第一個C++程序
  下一篇:go  道哥點評:全球比特幣勒索事件暴露迷信物理隔離不靠譜