一個Istio請求的生命週期 - 從雲提供商的SLB到istio-ingressgateway

開源項目推薦

Pepper Metrics是我與同事開發的一個開源工具(github.com/zrbcool/pep…),其經過收集jedis/mybatis/httpservlet/dubbo/motan的運行性能統計,並暴露成prometheus等主流時序數據庫兼容數據,經過grafana展現趨勢。其插件化的架構也很是方便使用者擴展並集成其餘開源組件。
請你們給個star,同時歡迎你們成爲開發者提交PR一塊兒完善項目。node

簡介

隨着Service Mesh的概念逐漸被你們所接受,以及K8S做爲一個容器管理平臺已經成爲事實標準,你們對於K8S下的服務治理及流量管理的需求也是日漸強烈,在Google,IBM,Lyft幾個大廠的推進下,Istio + Envoy的Service Mesh及流量管理的解決方案補齊了K8S在服務治理,精細化的流量管理,灰度發佈等高級特性上的不足,因爲其Go加C++語言棧的優點,相比Linked的scala更節省資源,目前已經基本能夠肯定是Service Mesh領域的事實標準。
本篇文章,我以在阿里雲建立的K8S加Istio的集羣環境爲例,來說一下一個請求到底在K8S以及Istio、Envoy和微服務的Pod之間網絡上是如何流轉的。linux

基礎知識說明

本文中忽略了大量網絡及Kubernates中的概念及網絡實現原理的說明,若是讀者在閱讀中遇到困難,請參考下面列出的幾篇文章git

  • Iptables/Netfilter(www.zsythink.net/archives/11…
  • 網橋
  • Veth設備對
  • linux網絡命名空間
  • Kubernetes的cni網絡插件機制及Flannel實現(阿里雲使用type爲Alloc的Flannel實現)
  • Kubernetes中的Service(包含LoadBalancer,NodePort,ClusterIP),Pod,Deployment等概念
  • Service Mesh的概念
  • Istio & Envoy

示例說明

新建立集羣名爲test,下面有兩個node節點,主機名分別爲work001,和work002,(經過阿里雲容器服務Kubernetes版的應用市場)部署istio-ingressgateway並建立type爲LoadBalancer的Service,以及部署replics爲2的istio-ingressgateway POD實例,完成後可見兩個POD實例分別在work001及work002上啓動。
建立成功後,會在阿里雲控制檯上發現,LoadBalancer類型的Service會自動爲咱們建立好一個阿里雲負載均衡(182.92.251.227)實例並將咱們的兩個node節點的31061端口做爲阿里雲負載均衡實例的後端服務,以下圖所示:
github

根據上面描述我將信息整理成下圖所示,圖中紅線部分是今天這篇文章要描述的請求網絡流轉路徑

請求從外網到SLB到work001

從work001(上圖中的192.168.0.17)這臺機器查看iptables規則能夠看到:docker

➜  ~ iptables -L -t nat
Chain PREROUTING (policy ACCEPT 244 packets, 14640 bytes)
 pkts bytes target     prot opt in     out     source               destination         
  32M 2003M KUBE-SERVICES  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service portals */
複製代碼

從eth0到cni0網橋

上面是一段nat表的規則,它的意思是,接受全部到來的數據,並交給KUBE-SERVICES這個規則鏈處理,下面咱們看下KUBE-SERVICES這個規則鏈:數據庫

Chain KUBE-SERVICES (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-FW-HBO2MBMQRZFAHKF2  tcp  --  *      *       0.0.0.0/0            182.92.251.227       /* default/istio-ingressgateway:http2 loadbalancer IP */ tcp dpt:80
  562 33720 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
複製代碼

能夠看到目標是182.92.251.227:80的請求表要被轉發給KUBE-FW-HBO2MBMQRZFAHKF2這個規則鏈,繼續看KUBE-FW-HBO2MBMQRZFAHKF2:後端

Chain KUBE-FW-HBO2MBMQRZFAHKF2 (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-XLB-HBO2MBMQRZFAHKF2  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/istio-ingressgateway:http2 loadbalancer IP */
    0     0 KUBE-MARK-DROP  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/istio-ingressgateway:http2 loadbalancer IP */
Chain KUBE-MARK-DROP (7 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x8000
複製代碼

上面規則表示請求包轉交給規則鏈KUBE-XLB-HBO2MBMQRZFAHKF2處理,若是不能匹配則丟棄(KUBE-MARK-DROP)tomcat

Chain KUBE-XLB-HBO2MBMQRZFAHKF2 (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-SVC-HBO2MBMQRZFAHKF2  all  --  *      *       172.20.0.0/16        0.0.0.0/0            /* Redirect pods trying to reach external loadbalancer VIP to clusterIP */
   80  4800 KUBE-SEP-EW7YLHH65NRUVIFQ  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* Balancing rule 0 for default/istio-ingressgateway:http2 */
複製代碼

能夠看到該規則鏈有兩條規則,因爲咱們的請求來自於集羣外,經過SLB(182.92.251.227:80)進入集羣,因此匹配第二條規則KUBE-SEP-EW7YLHH65NRUVIFQbash

Chain KUBE-SEP-EW7YLHH65NRUVIFQ (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-MARK-MASQ  all  --  *      *       172.20.1.157         0.0.0.0/0            /* default/istio-ingressgateway:http2 */
   80  4800 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* default/istio-ingressgateway:http2 */ tcp to:172.20.1.157:80

Chain KUBE-MARK-MASQ (102 references)
 pkts bytes target     prot opt in     out     source               destination         
  241 14460 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK or 0x4000
複製代碼

咱們的請求包匹配DNAT這條,DNAT將咱們的請求目標地址轉換爲172.20.1.157:80,並交給上層協議棧處理,這樣請求會走到routing decision(下面截圖來自於維基百科中大牛整理的Iptables/Netfilter的流轉圖) 網絡

work001的路由信息如圖所示

# work001
➜  ~ ip route
default via 192.168.0.253 dev eth0 
169.254.0.0/16 dev eth0 scope link metric 1002 
169.254.123.0/24 dev docker0 proto kernel scope link src 169.254.123.1 
172.20.1.128/25 dev cni0 proto kernel scope link src 172.20.1.129 
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.17
複製代碼

因爲172.20.1.157:80知足第三條172.20.1.128/25 dev cni0 proto kernel scope link src 172.20.1.129,該請求將直接交給網橋設備cni0(ip是172.20.1.129)處理
這樣請求就來到了cni0網橋

從cni0網橋到POD容器

➜  ~ kubectl get pods -o wide
NAME                                      READY     STATUS    RESTARTS   AGE       IP             NODE                                NOMINATED NODE
caf-sample-mesh-tomcat-77ff76b78f-fhgcl   2/2       Running   0          7d        172.20.1.167   cn-beijing.i-2zef83gtte2gddxlpy3q   <none>
istio-ingressgateway-84b4868f6b-9xnts     1/1       Running   0          15d       172.20.1.157   cn-beijing.i-2zef83gtte2gddxlpy3q   <none>
istio-ingressgateway-84b4868f6b-qxz5t     1/1       Running   0          22h       172.20.2.7     cn-beijing.i-2zeg4wnagly6jvlcz5kr   <none>
zookeeper-854f49888f-4zhhk                2/2       Running   0          8d        172.20.1.165   cn-beijing.i-2zef83gtte2gddxlpy3q   <none>
複製代碼

可以看到172.20.1.157這個IP由這個istio-ingressgateway-84b4868f6b-9xnts POD持有,進入這個POD,

➜  ~ kubectl exec -it istio-ingressgateway-84b4868f6b-9xnts bash
root@istio-ingressgateway-84b4868f6b-9xnts:/# ip route
default via 172.20.1.129 dev eth0 
172.20.0.0/16 via 172.20.1.129 dev eth0 
172.20.1.128/25 dev eth0  proto kernel  scope link  src 172.20.1.157 
複製代碼

咱們知道K8S內的eth0網卡實際上是veth設備對的一邊放在了POD的網絡namespace內,而且重命名成eth0,另外一端在宿主機上插在網橋cni0上,從宿主機上能夠查看

➜  ~ brctl show
bridge name	bridge id		STP enabled	interfaces
cni0		8000.0a58ac140181	no		veth0982819b
							veth21f3386e
							veth295aca54
							veth29c64f6d
							veth2fc83624
							veth5413f391
							veth55b5c32f
							veth5d630032
							veth5f4b9957
							veth67b85819
							veth6e5e5662
							veth6efeda57
							veth7413a550
							veth831d20f5
							veth849fecd0
							veth8dbe1d2c
							vetha7ec9173
							vetha83f9559
							vethcc9d3b42
							vethd967d407
							vethec751a37
							vethf69ed27b
複製代碼

這時網橋cni0其實充當了二層交換機設備,全部發往cni0的數據包會路由給相應的veth對的另外一邊,也就是在容器POD的網絡namespace內的eth0網卡,咱們的示例中是:POD istio-ingressgateway-84b4868f6b-9xnts(IP爲172.20.1.157)

總結

歷經重重關卡,咱們的請求包終於到達istio-ingressgateway容器內部,下面來總結下:
本講咱們主要介紹了,外網(集羣外)請求包如何經過阿里雲的四層負載均衡設備SLB轉發到咱們集羣內的POD(實際上是istio-ingressgateway)中,也就是咱們Service Mesh理念中常說的南北向流量,其實這塊的網絡轉發所有是由阿里雲的LoadBalancer(K8s的一種Service類型,由各個雲提供商來實現)以及K8s的cni網絡插件來實現的,目前還沒Istio什麼事

下一講咱們就來介紹下這個請求包在istio-ingressgateway中是如何流轉,及istio如何控制這個南北向流量的,敬請期待吧

相關文章
相關標籤/搜索