談談kubernets的service組件的Virtual IP

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
  • Service
  • kube-proxy
  • NodePort

k8s的pod可以有多個副本,但是在訪問pod時,會有幾個問題:

  • 用戶端需要知道各個pod的地址
  • 某一node上的pod如果故障,用戶端需要感知

為瞭解決這個問題,k8s引入了service的概念,用以指導用戶端的流量。

Service

以下面的my-nginx為例。

pod和service的定義檔案如下:

[root@localhost k8s]# cat run-my-nginx.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  name: my-nginxspec:  replicas: 2  template:    metadata:      labels:        run: my-nginx    spec:      containers:      - name: my-nginx        image: nginx        ports:        - containerPort: 80[root@localhost k8s]# cat run-my-nginx-service.yamlapiVersion: v1kind: Servicemetadata:  name: my-nginx  labels:    run: my-nginxspec:  ports:  - port: 80    protocol: TCP  selector:    run: my-nginx

pod my-nginx定義的replicas為2即2個副本,連接埠號碼為80;service my-nginx定義的selector為run: my-nginx,即該service選中所有label為run: my-nginx的pod;定義的port為80。

使用kubectl create -f xx.yml建立後,可以在叢集上看到2個pod,地址分別為10.244.1.10/10.244.2.10;可以看到1個service,IP/Port為10.11.97.177/80,其對接的Endpoints為10.244.1.10:80,10.244.2.10:80,即2個pod的服務地址,這三個URL在叢集內任一節點都可以使用curl訪問。

[root@localhost k8s]# kubectl get pods -n default -o wideNAME                       READY     STATUS    RESTARTS   AGE       IP            NODEmy-nginx-379829228-3n755   1/1       Running   0          21h       10.244.1.10   note2my-nginx-379829228-xh214   1/1       Running   0          21h       10.244.2.10   node1[root@localhost ~]#[root@localhost ~]# kubectl describe svc my-nginxName:                   my-nginxNamespace:              defaultLabels:                 run=my-nginxSelector:               run=my-nginxType:                   ClusterIPIP:                     10.11.97.177Port:                   <unset> 80/TCPEndpoints:              10.244.1.10:80,10.244.2.10:80Session Affinity:       None

但是,如果你去查看叢集各節點的IP資訊,是找不到10.11.97.177這個IP的,那麼curl是如何通過這個(Virtual)IP地址訪問到後端的Endpoints呢?

答案在這裡。

kube-proxy

k8s支援2種proxy模式,userspace和iptables。從v1.2版本開始,預設採用iptables proxy。那麼這兩種模式有什麼不同嗎?

1、userspace

顧名思義,userspace即使用者空間。為什麼這麼叫呢?看下面的圖。

kube-proxy會為每個service隨機監聽一個連接埠(proxy port ),並增加一條iptables規則:所以到clusterIP:Port 的報文都redirect到proxy port;kube-proxy從它監聽的proxy port收到報文後,走round robin(預設)或者session affinity(會話親和力,即同一client IP都走同一鏈路給同一pod服務),分發給對應的pod。

顯然userspace會造成所有報文都走一遍使用者態,效能不高,現在k8s已經不再使用了。

2、iptables

我們回過頭來看看userspace,既然使用者態會增加效能損耗,那麼有沒有辦法不走呢?實際上使用者態也只是一個報文LB,通過iptables完全可以搞定。k8s下面這張圖很清晰的說明了iptables方式與userspace方式的不同:kube-proxy只是作為controller,而不是server,真正服務的是核心的netfilter,體現在使用者態則是iptables。

kube-proxy的iptables方式也支援round robin(預設)和session affinity。

那麼iptables是怎麼做到LB,而且還能round-robin呢?我們通過iptables-save來看my-nginx這個服務在某一個node上的iptables規則。

-A KUBE-SERVICES -d 10.11.97.177/32 -p tcp -m comment --comment "default/my-nginx: cluster IP" -m tcp --dport 80 -j KUBE-SVC-BEPXDJBUHFCSYIC3-A KUBE-SVC-BEPXDJBUHFCSYIC3 -m comment --comment "default/my-nginx:" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-U4UWLP4OR3LOJBXU-A KUBE-SVC-BEPXDJBUHFCSYIC3 -m comment --comment "default/my-nginx:" -j KUBE-SEP-QHRWSLKOO5YUPI7O-A KUBE-SEP-U4UWLP4OR3LOJBXU -s 10.244.1.10/32 -m comment --comment "default/my-nginx:" -j KUBE-MARK-MASQ-A KUBE-SEP-U4UWLP4OR3LOJBXU -p tcp -m comment --comment "default/my-nginx:" -m tcp -j DNAT --to-destination 10.244.1.10:80-A KUBE-SEP-QHRWSLKOO5YUPI7O -s 10.244.2.10/32 -m comment --comment "default/my-nginx:" -j KUBE-MARK-MASQ-A KUBE-SEP-QHRWSLKOO5YUPI7O -p tcp -m comment --comment "default/my-nginx:" -m tcp -j DNAT --to-destination 10.244.2.10:80

第1條規則,終於看到這個virtual IP了。node上不需要有這個ip地址,iptables在看到目的地址為virutal ip的符合規則tcp報文,會走KUBE-SVC-BEPXDJBUHFCSYIC3規則。

第2/3條規則,KUBE-SVC-BEPXDJBUHFCSYIC3鏈實現了將報文按50%的統計機率隨機匹配到2條規則(round-robin)。

第4/5和5/6為成對的2組規則,將報文轉給了真正的服務pod。

至此,從物理node收到目的地址為10.11.97.177、連接埠號碼為80的報文開始,到pod my-nginx收到報文並響應,描述了一個完整的鏈路。可以看到,整個報文鏈路上沒有經過任何使用者態進程,效率和穩定性都比較高。

NodePort

上面的例子裡,由於10.11.97.177其實還是在叢集內有效地址,由於實際上並不存在這個地址,當從叢集外訪問時會訪問失敗,這時需要將service暴漏出去。k8s給出的一個方案是NodePort,用戶端根據NodePort+叢集內任一物理節點的IP,就可以訪問k8s的service了。這又是怎麼做到的呢?

答案還是iptables。我們來看下面這個sock-shop的例子,其建立方法見k8s.io,不再贅述。

[root@localhost k8s]# kubectl describe svc front-end -n sock-shopName:                   front-endNamespace:              sock-shopLabels:                 name=front-endSelector:               name=front-endType:                   NodePortIP:                     10.15.9.0Port:                   <unset> 80/TCPNodePort:               <unset> 30001/TCPEndpoints:              10.244.2.5:8079Session Affinity:       None

在任一node上查看iptables-save:

-A KUBE-NODEPORTS -p tcp -m comment --comment "sock-shop/front-end:" -m tcp --dport 30001 -j KUBE-MARK-MASQ-A KUBE-NODEPORTS -p tcp -m comment --comment "sock-shop/front-end:" -m tcp --dport 30001 -j KUBE-SVC-LFMD53S3EZEAOUSJ-A KUBE-SERVICES -d 10.15.9.0/32 -p tcp -m comment --comment "sock-shop/front-end: cluster IP" -m tcp --dport 80 -j KUBE-SVC-LFMD53S3EZEAOUSJ-A KUBE-SVC-LFMD53S3EZEAOUSJ -m comment --comment "sock-shop/front-end:" -j KUBE-SEP-SM6TGF2R62ADFGQA-A KUBE-SEP-SM6TGF2R62ADFGQA -s 10.244.2.5/32 -m comment --comment "sock-shop/front-end:" -j KUBE-MARK-MASQ-A KUBE-SEP-SM6TGF2R62ADFGQA -p tcp -m comment --comment "sock-shop/front-end:" -m tcp -j DNAT --to-destination 10.244.2.5:8079

聰明如你,一定已經看明白了吧。

不過kube-proxy的iptables有個缺陷,即當pod故障時無法自動重試,需要依賴readiness probes,主要思想就是建立一個探測容器,當檢測到後端pod掛了的時候,更新iptables。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.