<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Kubernetes學(xué)習(xí)筆記之kube-proxy service實現(xiàn)原理

          共 8120字,需瀏覽 17分鐘

           ·

          2021-05-23 15:05

          點擊“程序員面試吧”,選擇“星標??”

          點擊文末“閱讀原文”解鎖資料!

          1. Overview

          我們生產(chǎn)k8s對外暴露服務(wù)有多種方式,其中一種使用external-ips clusterip service ClusterIP Service方式對外暴露服務(wù),kube-proxy使用iptables mode。這樣external ips可以指定固定幾臺worker節(jié)點的IP地址(worker節(jié)點服務(wù)已經(jīng)被驅(qū)逐,作為流量轉(zhuǎn)發(fā)節(jié)點不作為計算節(jié)點),并作為lvs vip下的rs來負載均衡。根據(jù)vip:port來訪問服務(wù),并且根據(jù)port不同來區(qū)分業(yè)務(wù)。相比于NodePort Service那樣可以通過所有worker節(jié)點的node_ip:port來訪問更高效,也更容易落地生產(chǎn)。但是,traffic packet是怎么根據(jù)集群外worker節(jié)點的node_ip:port或者集群內(nèi)cluster_ip:port訪問方式找到pod ip的?

          并且,我們生產(chǎn)k8s使用calico來作為cni插件,采用 Peered with TOR (Top of Rack) routers方式部署,每一個worker node和其置頂交換機建立bgp peer配對,置頂交換機會繼續(xù)和上層核心交換機建立bgp peer配對,這樣可以保證pod ip在公司內(nèi)網(wǎng)可以直接被訪問。

          但是,traffic packet知道了pod ip,又是怎么跳到pod的呢?

          以上問題可以歸并為一個問題:數(shù)據(jù)包是怎么一步步跳轉(zhuǎn)到pod的?很長時間以來,一直在思考這些問題。

          2. 原理分析

          實際上答案很簡單:訪問業(yè)務(wù)服務(wù)vip:port或者說node_ip:port,當packet到達node_ip所在機器如worker A節(jié)點時,會根據(jù)iptable rules一步步找到pod ip;找到了pod ip后,由于使用calico bgp部署方式,核心交換機和置頂交換機都有該pod ip所在的ip段的路由,packet最后會跳轉(zhuǎn)到某一個worker節(jié)點比如worker B,而worker B上有calico早就寫好的路由規(guī)則route和虛擬網(wǎng)卡virtual interface,再根據(jù)veth pair從而由host network namespace跳轉(zhuǎn)到pod network namespace,從而跳轉(zhuǎn)到對應(yīng)的pod。

          首先可以本地部署個k8s集群模擬測試下,這里使用 install minikube with calico

          minikube start --network-plugin=cni --cni=calico
          # 或者
          minikube start --network-plugin=cni
          kubectl apply -f https://docs.projectcalico.org/manifests/calico.yaml

          然后部署個業(yè)務(wù)pod,這里使用nginx為例,副本數(shù)為2,并創(chuàng)建ClusterIP Service with ExternalIPs和NodePort Service:

          ---
          apiVersion: apps/v1
          kind: Deployment
          metadata:
            name: nginx-demo-1
            labels:
              app: nginx-demo-1
          spec:
            replicas: 2
            template:
              metadata:
                name: nginx-demo-1
                labels:
                  app: nginx-demo-1
              spec:
                containers:
                  - name: nginx-demo-1
                    image: nginx:1.17.8
                    imagePullPolicy: IfNotPresent
                    livenessProbe:
                      httpGet:
                        port: 80
                        path: /index.html
                      failureThreshold: 10
                      initialDelaySeconds: 10
                      periodSeconds: 10
                restartPolicy: Always
            selector:
              matchLabels:
                app: nginx-demo-1
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: nginx-demo-1
          spec:
            selector:
              app: nginx-demo-1
            ports:
              - port: 8088
                targetPort: 80
                protocol: TCP
            type: ClusterIP
            externalIPs:
              - 192.168.64.57 # 這里worker節(jié)點ip可以通過 minikube ip 查看,這里填寫你自己的worker節(jié)點ip地址
          ---
          apiVersion: v1
          kind: Service
          metadata:
            name: nginx-demo-2
          spec:
            selector:
              app: nginx-demo-1
            ports:
              - port: 8089
                targetPort: 80
            type: NodePort
          ---

          部署完成后,就可以通過 ExternalIP ClusterIP Service或者NodePort Service兩種方式訪問業(yè)務(wù)服務(wù):

          3. iptables寫自定義規(guī)則

          當數(shù)據(jù)包通過node_ip:port或者cluster_ip:port訪問服務(wù)時,會在當前worker節(jié)點被內(nèi)核DNAT(Destination Network Address Translation)為pod ip,反向packet又會被SNAT(Source Network Address Translation)。這里借用calico官網(wǎng)的非常生動的兩張圖說明About Kubernetes Services :

          cluster-ip service 訪問流程:

          node-port service 訪問流程:

          由于我們生產(chǎn)k8s的kube-proxy使用iptables mode,所以這些snat/dnat規(guī)則是kube-proxy進程通過調(diào)用iptables命令來實現(xiàn)的。iptables使用各種chain來管理大量的iptable rules,主要是五鏈四表,五鏈包括:prerouting/input/output/forward/postrouting chain,四表包括:

          raw/mangle/nat/filter table,同時也可以用戶自定義chain。數(shù)據(jù)包packet進過內(nèi)核時經(jīng)過五鏈四表流程圖如下:

          而kube-proxy進程會在nat table內(nèi)自定義KUBE-SERVICES chain,并在PREROUTING內(nèi)生效,可以通過命令查看,然后在查看KUBE-SERVICES chain中的規(guī)則:


          sudo iptables -v -n -t nat -L PREROUTING | grep KUBE-SERVICES

          sudo iptables -v -n -t nat -L KUBE-SERVICES

          sudo iptables -v -n -t nat -L KUBE-NODEPORTS

          可以看到,如果在集群內(nèi)通過cluster_ip:port即10.196.52.1:8088,或者在集群外通過external_ip:port即192.168.64.57:8088方式訪問服務(wù),都會在內(nèi)核里匹配到 KUBE-SVC-JKOCBQALQGD3X3RT chain的規(guī)則,這個對應(yīng)nginx-demo-1 service;如果是在集群內(nèi)通過cluster_ip:port即10.196.89.31:8089,或者集群外通過nodeport_ip:port即192.168.64.57:31755方式訪問服務(wù),會匹配到 KUBE-SVC-6JCCLZMUQSW27LLD chain的規(guī)則,這個對應(yīng)nginx-demo-2 service:

          然后繼續(xù)查找 KUBE-SVC-JKOCBQALQGD3X3RT chain和 KUBE-SVC-6JCCLZMUQSW27LLD chain的規(guī)則,發(fā)現(xiàn)每一個 KUBE-SVC-xxx 都會跳轉(zhuǎn)到 KUBE-SEP-xxx chain上,并且因為pod副本數(shù)是2,這里就會有兩個 KUBE-SEP-xxx chain,并且以50%概率跳轉(zhuǎn)到任何一個 KUBE-SEP-xxx chain,即rr(round robin)負載均衡算法,這里kube-proxy使用iptables statistic module來設(shè)置的,最后就會跳轉(zhuǎn)到pod ip 10.217.120.72:80(這里假設(shè)訪問這個pod)。總之,經(jīng)過kube-proxy調(diào)用iptables命令,根據(jù)service/endpoint設(shè)置對應(yīng)的chain,最終一步步跳轉(zhuǎn)到pod ip,從而數(shù)據(jù)包packet下一跳是該pod ip:

          sudo iptables -v -n -t nat -L KUBE-SVC-JKOCBQALQGD3X3RT
          sudo iptables -v -n -t nat -L KUBE-SEP-CRT5ID3374EWFAWN

          sudo iptables -v -n -t nat -L KUBE-SVC-6JCCLZMUQSW27LLD
          sudo iptables -v -n -t nat -L KUBE-SEP-SRE6BJUIAABTZ4UR

          總之,不管是通過cluster_ip:port、external_ip:port還是node_ip:port方式訪問業(yè)務(wù)服務(wù),packet通過kube-proxy進程自定義的各種chain找到了下一跳pod ip地址。

          但是,packet如何知道這個pod ip在哪個節(jié)點呢?

          4. calico寫自定義routers和virtual interface

          上文已經(jīng)說過,我們部署calico方式可以保證pod ip在集群外是可以被路由的,這是因為交換機上會有node level的路由規(guī)則,在交換機上執(zhí)行 dis bgp routing-table會有類似如下路由規(guī)則。表示如果訪問 10.20.30.40/26 pod網(wǎng)段下一跳是worker B的IP地址。這些路由規(guī)則是部署在每一個worker節(jié)點的bird進程(bgp client)分發(fā)的,交換機通過BGP學(xué)習(xí)來的:

          # 這里是隨機編造的地址
          Network                 NextHop         ...
          10.20.30.40/26          10.203.30.40    ...

          所以,packet在知道了pod ip 10.217.120.72:80 后(這里假設(shè)訪問了pod nginx-demo-1-7f67f8bdd8-fxptt),很容易找到了worker B節(jié)點,本文章示例即是minikube節(jié)點。查看該節(jié)點的路由表和網(wǎng)卡,找到了在host network namespace這一側(cè)是網(wǎng)卡 cali1087c975dd9,編號是13,這個編號很重要,可以通過編號知道這個veth pair的另一端在哪個pod network namespace。發(fā)現(xiàn) pod nginx-demo-1-7f67f8bdd8-fxptt 的網(wǎng)卡eth0就是veth pair的另一端,并且編號也是13:


          # 因為該nginx容器沒有ifconfig命令和ip命令,可以創(chuàng)建nicolaka/netshoot:latest 容器并加入到該nginx container的namespace中
          docker ps -a | grep nginx
          export CONTAINER_ID=f2ece695e8b9 # 這里是nginx container的container id
          # nicolaka/netshoot:latest鏡像地址github.com/nicolaka/netshoot
          docker run -it --network=container:$CONTAINER_ID --pid=container:$CONTAINER_ID --ipc=container:$CONTAINER_ID nicolaka/netshoot:latest ip -c addr
          ip -c addr

          以上路由表規(guī)則和虛擬網(wǎng)卡是calico cni的calico network plugin創(chuàng)建的,而pod ip以及每一個node的pod ip cidr網(wǎng)段都是由calico ipam plugin創(chuàng)建管理的,并且這些數(shù)據(jù)會寫入calico datastore內(nèi)。至于calico network plugin和calico ipam plugin具體是如何做的,后續(xù)有時間再記錄學(xué)習(xí)。

          5. 總結(jié)

          不管集群內(nèi)cluster_ip:port,還是集群外external_ip:port或node_ip:port方式訪問服務(wù),都是會通過kube-proxy進程設(shè)置的各種iptables rules后跳轉(zhuǎn)到對應(yīng)的pod ip,然后借助于calico bgp部署方式跳轉(zhuǎn)到目標pod所在worker節(jié)點,并通過該節(jié)點的路由表和虛擬網(wǎng)卡,找到對應(yīng)的那個pod,packet由host network namespace再跳轉(zhuǎn)到pod network namespace。一直以來的有關(guān)service和calico疑問也算是搞明白了。

          參考鏈接

          • https://docs.projectcalico.org/about/about-kubernetes-service

          • https://mp.weixin.qq.com/s/bYZJ1ipx7iBPw6JXiZ3Qu

          • https://mp.weixin.qq.com/s/oaW87xLnlUYYrwVjBnqee

          • https://mp.weixin.qq.com/s/RziLRPYqNoQEQuncm47rHg

          文章轉(zhuǎn)載:360云計算

          (版權(quán)歸原作者所有,侵刪)


          點擊下方“閱讀原文”查看更多

          瀏覽 44
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  西西444WWW无码高清视频 | 亚洲 精品 综合 精品 自拍 | 色婷婷丁香五月天在线观看 | 成人在线免费观看黄片 | 亚洲三级久久 |