Istio 网关中的 Gateway 和 VirtualService 配置深度解析
原文鏈接:請求都去哪了?
通過前幾篇文章的學習與實踐,我們對 Gateway、VirtualService 和 Destinationrule 的概念和原理有了初步的認知,本篇將對這幾個對象資源的配置文件進行深度地解析,具體細節(jié)將會深入到每一個配置項與 Envoy 配置項的映射關系。
在開始之前,需要先搞清楚我們創(chuàng)建的這些對象資源最后都交給誰來處理了,負責處理這些資源的就是 pilot。
1. pilot總體架構
首先我們回顧一下 pilot 總體架構,上面是官方關于pilot的架構圖,因為是 old_pilot_repo 目錄下,可能與最新架構有出入,僅供參考。所謂的 pilot 包含兩個組件:pilot-agent 和 pilot-discovery。圖里的 agent 對應 pilot-agent 二進制,proxy 對應 Envoy 二進制,它們兩個在同一個容器中,discovery service 對應 pilot-discovery 二進制,在另外一個跟應用分開部署的單獨的 Deployment 中。
- discovery service : 從 Kubernetes apiserver list/watch service、endpoint、pod、node 等資源信息,監(jiān)聽 istio 控制平面配置信息(如VirtualService、DestinationRule等), 翻譯為 Envoy 可以直接理解的配置格式。
- proxy : 也就是 Envoy,直接連接 discovery service,間接地從 Kubernetes 等服務注冊中心獲取集群中微服務的注冊情況。
- agent : 生成 Envoy 配置文件,管理 Envoy 生命周期。
- service A/B : 使用了 Istio 的應用,如 Service A/B,的進出網絡流量會被 proxy 接管。
簡單來說 Istio 做為管理面,集合了配置中心和服務中心兩個功能,并把配置發(fā)現(xiàn)和服務發(fā)現(xiàn)以一組統(tǒng)一的 xDS 接口提供出來,數(shù)據(jù)面的 Envoy 通過 xDS 獲取需要的信息來做服務間通信和服務治理。
2. pilot-discovery 為 Envoy 提供的 xds 服務
所謂 xds
pilot-discovery 為數(shù)據(jù)面(運行在 sidecar 中的 Envoy 等 proxy 組件)提供控制信息服務,也就是所謂的 discovery service 或者 xds 服務。這里的 x 是一個代詞,類似云計算里的 XaaS 可以指代 IaaS、PaaS、SaaS 等。在 Istio 中,xds 包括 cds(cluster discovery service)、lds(listener discovery service)、rds(route discovery service)、eds(endpoint discovery service),而 ads(aggregated discovery service) 是對這些服務的一個統(tǒng)一封裝。
以上 cluster、endpoint、route 等概念的詳細介紹和實現(xiàn)細節(jié)可以參考 Envoy 在社區(qū)推廣的 data plane api(github.com/envoyproxy/…),這里只做簡單介紹:
- endpoint : 一個具體的“應用實例”,對應 ip 和端口號,類似 Kubernetes 中的一個 Pod。
- cluster : 一個 cluster 是一個“應用集群”,它對應提供相同服務的一個或多個 endpoint。cluster 類似 Kubernetes 中 Service 的概念,即一個 Kubernetes Service 對應一個或多個用同一鏡像啟動,提供相同服務的 Pod。
- route : 當我們做灰度發(fā)布、金絲雀發(fā)布時,同一個服務會同時運行多個版本,每個版本對應一個 cluster。這時需要通過 route 規(guī)則規(guī)定請求如何路由到其中的某個版本的 cluster 上。
以上這些內容實際上都是對 Envoy 等 proxy 的配置信息,而所謂的 cluster discovery service、route discovery service 等 xxx discovery service 就是 Envoy 等從 pilot-discovery 動態(tài)獲取 endpoint、cluster 等配置信息的協(xié)議和實現(xiàn)。為什么要做動態(tài)配置加載,自然是為了使用 istioctl 等工具統(tǒng)一、靈活地配置 service mesh。至于如何通過 istioctl 來查看 xds 信息,下文將會詳細介紹。
而為什么要用 ads 來“聚合”一系列 xds,并非僅為了在同一個 gRPC 連接上實現(xiàn)多種 xds 來省下幾個網絡連接,ads 還有一個非常重要的作用是解決 cds、rds 信息更新順序依賴的問題,從而保證以一定的順序同步各類配置信息,這方面的討論可以詳見 Envoy官網。
如何查看 xds
pilot-discovery 在初始化階段依次 init 了各種模塊,其中 discovery service 就是 xDS 相關實現(xiàn)。envoy API reference 可以查到 v1 和 v2 兩個版本的 API 文檔。envoy control plane 給了 v2 grpc 接口相關的數(shù)據(jù)結構和接口。
那么如何查看 xds 的信息呢?雖然 v2 是 grpc 的接口,但是 pilot 提供了 InitDebug,可以通過 debug 接口查詢服務和 routes 等服務和配置信息。
查看 eds
首先找到 Service istio-pilot 的 Cluster IP:
$ export PILOT_SVC_IP=$(kubectl -n istio-system get svc istio-pilot -o go-template='{{.spec.clusterIP}}') 復制代碼然后查看 eds:
$ curl http://$PILOT_SVC_IP:8080/debug/edsz 復制代碼[{"clusterName": "outbound|9080||reviews.nino.svc.cluster.local","endpoints": [{"lbEndpoints": [{"endpoint": {"address": {"socketAddress": {"address": "10.244.0.56","portValue": 9080}}}}, {"endpoint": {"address": {"socketAddress": {"address": "10.244.0.58","portValue": 9080}}}}, {"endpoint": {"address": {"socketAddress": {"address": "10.244.2.25","portValue": 9080}}}}]}] }, {"clusterName": "outbound|9080|v3|reviews.nino.svc.cluster.local","endpoints": [{"lbEndpoints": [{"endpoint": {"address": {"socketAddress": {"address": "10.244.0.58","portValue": 9080}}}}]}] }] 復制代碼查看 cds
$ curl http://$PILOT_SVC_IP:8080/debug/cdsz 復制代碼[{"node": "sidecar~172.30.104.45~fortio-deploy-56dcc85457-b2pkc.default~default.svc.cluster.local-10", "addr": "172.30.104.45:43876", "connect": "2018-08-07 06:31:08.161483005 +0000 UTC m=+54.337448884","Clusters":[{"name": "outbound|9080||details.default.svc.cluster.local","type": "EDS","edsClusterConfig": {"edsConfig": {"ads": {}},"serviceName": "outbound|9080||details.default.svc.cluster.local"},"connectTimeout": "1.000s","circuitBreakers": {"thresholds": [{}]} }, ... {"name": "outbound|9090||prometheus-k8s.monitoring.svc.cluster.local","type": "EDS","edsClusterConfig": {"edsConfig": {"ads": {}},"serviceName": "outbound|9090||prometheus-k8s.monitoring.svc.cluster.local"},"connectTimeout": "1.000s","circuitBreakers": {"thresholds": [{}]} }, {"name": "BlackHoleCluster","connectTimeout": "5.000s" }]} ] 復制代碼查看 ads
$ curl http://$PILOT_SVC_IP:8080/debug/adsz 復制代碼3. Envoy 基本術語回顧
為了讓大家更容易理解后面所講的內容,先來回顧一下 Envoy 的基本術語。
- Listener : 監(jiān)聽器(listener)是服務(程序)監(jiān)聽者,就是真正干活的。 它是可以由下游客戶端連接的命名網絡位置(例如,端口、unix域套接字等)。Envoy 公開一個或多個下游主機連接的偵聽器。一般是每臺主機運行一個 Envoy,使用單進程運行,但是每個進程中可以啟動任意數(shù)量的 Listener(監(jiān)聽器),目前只監(jiān)聽 TCP,每個監(jiān)聽器都獨立配置一定數(shù)量的(L3/L4)網絡過濾器。Listenter 也可以通過 Listener Discovery Service(LDS)動態(tài)獲取。
- Listener filter : Listener 使用 listener filter(監(jiān)聽器過濾器)來操作鏈接的元數(shù)據(jù)。它的作用是在不更改 Envoy 的核心功能的情況下添加更多的集成功能。Listener filter 的 API 相對簡單,因為這些過濾器最終是在新接受的套接字上運行。在鏈中可以互相銜接以支持更復雜的場景,例如調用速率限制。Envoy 已經包含了多個監(jiān)聽器過濾器。
- Http Route Table : HTTP 的路由規(guī)則,例如請求的域名,Path 符合什么規(guī)則,轉發(fā)給哪個 Cluster。
- Cluster : 集群(cluster)是 Envoy 連接到的一組邏輯上相似的上游主機。Envoy 通過服務發(fā)現(xiàn)發(fā)現(xiàn)集群中的成員。Envoy 可以通過主動運行狀況檢查來確定集群成員的健康狀況。Envoy 如何將請求路由到集群成員由負載均衡策略確定。
更多詳細信息可以參考 Envoy 的架構與基本術語,本文重點突出 Listener、Route 和 Cluster 這三個基本術語,同時需要注意流量經過這些術語的先后順序,請求首先到達 Listener,然后通過 Http Route Table 轉到具體的 Cluster,最后由具體的 Cluster 對請求做出響應。
4. Gateway 和 VirtualService 配置解析
還是拿之前 Istio 流量管理 這篇文章中的例子來解析吧,首先創(chuàng)建了一個 Gateway,配置文件如下:
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: bookinfo-gateway spec: selector: istio: ingressgateway # use istio default controller servers: - port: number: 80 name: http protocol: HTTP hosts: - "*" 復制代碼然后又創(chuàng)建了一個 VirtualService:
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: bookinfo spec: hosts: - "*" gateways: - bookinfo-gateway http: - match: - uri: exact: /productpage - uri: exact: /login - uri: exact: /logout - uri: prefix: /api/v1/products route: - destination: host: productpage port: number: 9080 復制代碼VirtualService 映射的就是 Envoy 中的 Http Route Table,大家可以注意到上面的 VirtualService 配置文件中有一個 gateways 字段,如果有這個字段,就表示這個 Http Route Table 是綁在 ingressgateway 的 Listener 中的;如果沒有這個字段,就表示這個 Http Route Table 是綁在 Istio 所管理的所有微服務應用的 Pod 上的。
為了分清主次,我決定將本文拆分成兩篇文章來講解,本篇主要圍繞 ingressgateway 來解析 Gateway 和 VirtualService,而微服務應用本身的 VirtualService 和 DestinationRule 解析放到下一篇文章再說。
顯而易見,上面這個 VirtualService 映射的 Http Route Table 是被綁在 ingressgateway 中的,可以通過 istioctl 來查看,istioctl 的具體用法請參考:調試 Envoy 和 Pilot。
首先查看 Listener 的配置項:
$ istioctl -n istio-system pc listeners istio-ingressgateway-b6db8c46f-qcfks --port 80 -o json 復制代碼[{"name": "0.0.0.0_80","address": {"socketAddress": {"address": "0.0.0.0","portValue": 80}},"filterChains": [{"filters": [{"name": "envoy.http_connection_manager","config": {..."rds": {"config_source": {"ads": {}},"route_config_name": "http.80"},...}}]}]} ] 復制代碼通過 rds 配置項的 route_config_name 字段可以知道該 Listener 使用的 Http Route Table 的名字是 http.80。
查看 Http Route Table 配置項:
$ istioctl -n istio-system pc routes istio-ingressgateway-b6db8c46f-qcfks --name http.80 -o json 復制代碼[{"name": "http.80","virtualHosts": [{"name": "bookinfo:80","domains": ["*"],"routes": [{"match": {"path": "/productpage"},"route": {"cluster": "outbound|9080||productpage.default.svc.cluster.local","timeout": "0.000s","maxGrpcTimeout": "0.000s"},...},...{"match": {"prefix": "/api/v1/products"},"route": {"cluster": "outbound|9080||productpage.default.svc.cluster.local","timeout": "0.000s","maxGrpcTimeout": "0.000s"},...},...]}],"validateClusters": false} ] 復制代碼- VirtualService 中的 hosts 字段對應 Http Route Table 中 virtualHosts 配置項的 domains 字段。這里表示可以使用任何域名來通過 ingressgateway 訪問服務(也可以直接通過 IP 來訪問)。
- VirtualService 中的 exact 字段對應 Http Route Table 中 routes.match 配置項的 path 字段。
- VirtualService 中的 prefix 字段對應 Http Route Table 中 routes.match 配置項的 prefix 字段。
- VirtualService 中的 route.destination 配置項對應 Http Route Table 中 routes.route 配置項的 cluster 字段。
關于 Envoy 中的 HTTP 路由解析可以參考我之前的文章:HTTP 路由解析。
查看 Cluster 配置項:
$ istioctl -n istio-system pc clusters istio-ingressgateway-b6db8c46f-qcfks --fqdn productpage.default.svc.cluster.local --port 9080 -o json 復制代碼[{"name": "outbound|9080||productpage.default.svc.cluster.local","type": "EDS","edsClusterConfig": {"edsConfig": {"ads": {}},"serviceName": "outbound|9080||productpage.default.svc.cluster.local"},"connectTimeout": "1.000s","circuitBreakers": {"thresholds": [{}]}} ] 復制代碼可以看到,Cluster 最終將集群外通過 ingressgateway 發(fā)起的請求轉發(fā)給實際的 endpoint,也就是 Kubernetes 集群中的 Service productpage 下面的 Pod(由 serviceName 字段指定)。
實際上 istioctl 正是通過 pilot 的 xds 接口來查看 Listener 、Route 和 Cluster 等信息的。
好了,現(xiàn)在請求已經轉交給 productpage 了,那么接下來這個請求將會如何走完整個旅程呢?請聽下回分解!
5. 參考
- Service Mesh深度學習系列(三)| istio源碼分析之pilot-discovery模塊分析(中)
- 調試 Envoy 和 Pilot
- Envoy 的架構與基本術語
轉載于:https://juejin.im/post/5ca09524f265da30d561e8a4
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的Istio 网关中的 Gateway 和 VirtualService 配置深度解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Data Augmentation
- 下一篇: Qtum量子链AUR开发工具包即日上线