淺析Istio組件Envoy的流量管理
背景介紹
微服務(wù)架構(gòu)帶來的開發(fā)便捷性使業(yè)務(wù)功能的開發(fā)周期明顯縮短,通過對(duì)于云計(jì)算平臺(tái)架構(gòu)的原生優(yōu)化,讓業(yè)務(wù)功能的持續(xù)集成與交付更為敏捷。但同時(shí)微服務(wù)架構(gòu)也引入了服務(wù)治理的諸多問題:一個(gè)應(yīng)用由多個(gè)服務(wù)組成,每個(gè)服務(wù)有數(shù)個(gè)實(shí)例,每個(gè)實(shí)例的運(yùn)行狀態(tài)又在實(shí)時(shí)變化,這些催生了服務(wù)間通訊層的出現(xiàn)。通訊層既不與應(yīng)用程序代碼耦合,又能捕獲到底層環(huán)境的動(dòng)態(tài)變化并作出適當(dāng)?shù)恼{(diào)整,避免業(yè)務(wù)出現(xiàn)單點(diǎn)故障。
1.ServiceMesh簡(jiǎn)介
1.1服務(wù)網(wǎng)格(Service Mesh)簡(jiǎn)介
服務(wù)網(wǎng)絡(luò)是一個(gè)基礎(chǔ)設(shè)施層,用于處理服務(wù)間通信。云原生應(yīng)用有著復(fù)雜的服務(wù)拓?fù)?,服?wù)網(wǎng)格負(fù)責(zé)在這些拓?fù)渲袑?shí)現(xiàn)請(qǐng)求的可靠傳遞。在實(shí)踐中,服務(wù)網(wǎng)格通常實(shí)現(xiàn)為一組輕量級(jí)網(wǎng)絡(luò)代理,它們與應(yīng)用程序一起部署,但對(duì)應(yīng)用程序透明。

從局部看,服務(wù)網(wǎng)格技術(shù)就是在應(yīng)用節(jié)點(diǎn)上部署代理,應(yīng)用將請(qǐng)求發(fā)給代理,由代理完成點(diǎn)對(duì)點(diǎn)的路由轉(zhuǎn)發(fā)。

在上面的圖中,如果把左邊圖中的應(yīng)用程序去掉,只呈現(xiàn)出來代理和它們之間的調(diào)用關(guān)系(即右圖)。這時(shí)Service Mesh的概念就會(huì)清晰:代理和調(diào)用關(guān)系形成完整的網(wǎng)絡(luò),代表服務(wù)間復(fù)雜的調(diào)用關(guān)系,承載著系統(tǒng)內(nèi)的所有應(yīng)用。
1.2服務(wù)網(wǎng)絡(luò)架構(gòu)特點(diǎn)及優(yōu)勢(shì)
1)點(diǎn)對(duì)點(diǎn)通訊:沒有中心瓶頸。
2)對(duì)應(yīng)用無入侵:可以支持異構(gòu)技術(shù)產(chǎn)品的集成。同時(shí)對(duì)應(yīng)用透明,應(yīng)用開發(fā)不再需要關(guān)心復(fù)雜的網(wǎng)絡(luò)通訊實(shí)現(xiàn),可以專注業(yè)務(wù)邏輯的實(shí)現(xiàn)。
2.Istio及Envoy簡(jiǎn)介

Istio是一個(gè)由Google,IBM和Lyft團(tuán)隊(duì)合作開發(fā)的開源Service Mesh框架。目前已成為ServiceMesh的事實(shí)技術(shù)標(biāo)準(zhǔn),被廣泛應(yīng)用于各個(gè)行業(yè)的IT架構(gòu)。

Envoy 是用 C++語言開發(fā)的高性能代理,其內(nèi)置服務(wù)發(fā)現(xiàn)、負(fù)載均衡、TLS終止、HTTP/2、GRPC代理、熔斷器、健康檢查,基于百分比流量拆分的灰度發(fā)布、故障注入等功能,用于協(xié)調(diào)服務(wù)網(wǎng)格中所有服務(wù)的入站和出站流量。
3.Envoy流量管理的原理
3.1Iptables介紹
Istio調(diào)用Linux中的iptables進(jìn)行流量管理。iptables是一個(gè)運(yùn)行在用戶空間的應(yīng)用軟件,它通過控制Linux內(nèi)核netfilter模塊,來管理網(wǎng)絡(luò)數(shù)據(jù)包的流動(dòng)與轉(zhuǎn)送,實(shí)際上netfilter才是防火墻真正的安全框架。netfilter是Linux網(wǎng)絡(luò)安全大廈的基石,它提供了一整套鉤子(Hook)函數(shù)機(jī)制,IP層的5個(gè)鉤子點(diǎn)對(duì)應(yīng)了iptables的5個(gè)內(nèi)置鏈條:
- PREROUTING:在此DNAT。
 - POSTROUTING:在此SNAT。
 - INPUT:處理輸入給本地進(jìn)程的封包。
 - OUTPUT:處理本地進(jìn)程輸出的封包。
 - FORWARD:處理轉(zhuǎn)發(fā)給其他機(jī)器、其他網(wǎng)絡(luò)命名空間的封包。
 
3.2關(guān)于網(wǎng)絡(luò)入站的IP封包
從網(wǎng)絡(luò)入站的IP封包,先入TREOUTING鏈,而后進(jìn)行路由判斷:
1)如果封包路由目的地是本機(jī):則進(jìn)入INPUT鏈,然后發(fā)給本地進(jìn)程。
2)如果封包路由目的地不是本機(jī),并且啟用了IP轉(zhuǎn)發(fā),則進(jìn)入FORWARD鏈,然后通過POSTROUTING鏈,最后經(jīng)過網(wǎng)網(wǎng)絡(luò)接口發(fā)走。
3)對(duì)于本地進(jìn)程發(fā)往協(xié)議棧的封包,則首先通過OUTPUT鏈,然后通過POSTROUTING鏈,最后經(jīng)過網(wǎng)絡(luò)接口發(fā)走。
3.3關(guān)于自定義鏈
除此以外,我們還可以自定義鏈,但自定義鏈只能被某個(gè)默認(rèn)的鏈當(dāng)做動(dòng)作去調(diào)用才能起作用。
在Kubernetes中Istio通過Admission webhook的機(jī)制將Envoy Sidecar自動(dòng)注入,與應(yīng)用容器運(yùn)行于同一個(gè)Pod中,這種情況下它們將共享網(wǎng)絡(luò)名稱空間,因此也使用同一個(gè)網(wǎng)絡(luò)協(xié)議棧。
Istio 給應(yīng)用 Pod 注入的配置主要包括:
1)Init 容器 istio-init:用于Pod中設(shè)置iptables端口轉(zhuǎn)發(fā)。
2) Sidecar 容器 istio-proxy:運(yùn)行Envoy Sidecar代理。
3.4Iptables配置規(guī)則
在容器初始化后,我們進(jìn)入Sidecar容器切換為root用戶,查看配置的iptables規(guī)則。
iptables -t nat -S

ISTIO_INBOUND 鏈:對(duì)所有進(jìn)入Pod但非指定端口(如22)的流量全部重定向至15006端口(Envoy入口流量端口)進(jìn)行攔截處理。
ISTIO_OUTPUT 鏈:將由 istio-proxy 用戶空間發(fā)出且目的地不為localhost的Pod流出流量全部重定向至15001端口(envoy出口流量端口)。其他流量全部直接放行至下一個(gè)POSTROUTING鏈,不用被Envoy攔截處理。
整體流量流向示意圖如下圖所示:

1)進(jìn)入Pod的Inbound流量首先被PREROUTING鏈攔截并處理。
2)當(dāng)TCP請(qǐng)求進(jìn)入PREROUTING鏈時(shí)全部交給ISTIO_INBOUND處理。
-A PREROUTING -p tcp -j ISTIO_INBOUND
3)請(qǐng)求目標(biāo)端口非15008/22/15090/15021/15020的TCP請(qǐng)求全部交給ISTIO_IN_REDIRECT處理。
-A ISTIO_INBOUND -p tcp -j ISTIO_IN_REDIRECT
4)將發(fā)送到此的TCP請(qǐng)求全部重定向至15006端口(Envoy入口流量端口)
-A ISTIO_IN_REDIRECT -p tcp -j REDIRECT --to-ports 15006
5)在Envoy內(nèi)部處理后,決定將數(shù)據(jù)包轉(zhuǎn)發(fā)到應(yīng)用,這一步對(duì)Envoy來說屬于出口流量,會(huì)被netfilter攔截轉(zhuǎn)發(fā)至出口流量OUTPUT鏈。
6)出站請(qǐng)求,當(dāng)TCP請(qǐng)求進(jìn)入OUTPUT鏈時(shí)全部交給ISTIO_OUTPUT處理。
-A OUTPUT -p tcp -j ISTIO_OUTPUT
7)匹配出站請(qǐng)求對(duì)應(yīng)規(guī)則,請(qǐng)求本地服務(wù),出口為lo網(wǎng)卡同時(shí)來自istio-proxy用戶空間,流量返回到它的調(diào)用點(diǎn)中的下一條鏈執(zhí)行,即POSTROUTING鏈 。
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner
--gid-owner 1337 -j RETURN
8)Sidecar發(fā)出的請(qǐng)求到達(dá)目標(biāo)應(yīng)用。
9)目標(biāo)應(yīng)用處理完業(yè)務(wù)邏輯后響應(yīng)Sidecar,這一步對(duì)應(yīng)用來說屬于出口流量,再次被netfilter攔截轉(zhuǎn)發(fā)至出口流量OUTPUT鏈。
10) 出站請(qǐng)求,當(dāng)TCP請(qǐng)求進(jìn)入OUTPUT鏈時(shí)全部交給ISTIO_OUTPUT處理。
-A OUTPUT -p tcp -j ISTIO_OUTPUT
11)請(qǐng)求下一個(gè)服務(wù)/響應(yīng)請(qǐng)求,即請(qǐng)求非本地服務(wù)同時(shí)不來自istio-proxy用戶空間,流量被轉(zhuǎn)發(fā)至ISTIO_REDIRECT鏈。
-A ISTIO_OUTPUT -j ISTIO_REDIRECT
12)將重定向于此的TCP協(xié)議請(qǐng)求流量全部重定向至15001端口(Envoy出口流量端口)。
-A ISTIO_REDIRECT -p tcp -j REDIRECT --to-ports 15001
13)在Envoy內(nèi)部處理后,決定將數(shù)據(jù)包對(duì)外轉(zhuǎn)發(fā),這一步對(duì)Envoy來說屬于出口流量,會(huì)被netfilter攔截轉(zhuǎn)發(fā)至出口流量OUTPUT鏈。
14)出站請(qǐng)求,當(dāng)TCP請(qǐng)求進(jìn)入OUTPUT鏈時(shí)全部交給ISTIO_OUTPUT處理。
-A OUTPUT -p tcp -j ISTIO_OUTPUT
15)請(qǐng)求非本地的服務(wù),出口不為lo網(wǎng)卡同時(shí)來自istio-proxy用戶空間則跳過了ISTIO_REDIREC處理,直接RETURN到下一個(gè)鏈,即POSTROUTING鏈
-A ISTIO_OUTPUT -m owner --uid-owner 1337 -j RETURN -A ISTIO_OUTPUT -m owner
--gid-owner 1337 -j RETURN
16)POSTROUTING鏈處理完成后,根據(jù)路由表選擇合適的網(wǎng)卡發(fā)送Outbound流量。
4.總結(jié)
Envoy的核心工作內(nèi)容在于對(duì)業(yè)務(wù)透明的請(qǐng)求攔截,將所有進(jìn)出流量進(jìn)行管理。對(duì)攔截的請(qǐng)求進(jìn)行一定的規(guī)則進(jìn)行安全訪問控制、接入控制、流量控制等諸多方面處理后,發(fā)送給應(yīng)用程序。通過使用Envoy,可以使開發(fā)者專注于應(yīng)用功能的開發(fā),不用考慮復(fù)雜的網(wǎng)絡(luò)通訊。















 
 
 








 
 
 
 