Service Mesh(服务网格)——后 Kubernetes 时代的微服务
本文轉載自:宋凈超的博客
這不是一篇教程,本文試圖帶您梳理清楚 Kubernetes、Envoy(xDS 協議)以及 Istio Service Mesh 之間的關系及內在聯系。本文介紹了 Kubernetes 中的負載均衡方式,Envoy 的 xDS 協議對于 Service Mesh 的意義以及為什么說有了 Kubernetes 還需要 Istio。
Envoy 對于 Service Mesh 或者說 Cloud Native 最大的貢獻就是定義了 xDS,Envoy 雖然本質上是一個 proxy,但是它的配置協議被眾多開源軟件所支持,如 Istio、Linkerd、AWS App Mesh、SOFAMesh 等。
關于本文標題
2018年9月1日,Bilgin Ibryam 在 InfoQ 發表了一篇文章 Microservices in a Post-Kubernetes Era,中文版見后 Kubernetes 時代的微服務(譯文有些錯誤,僅供參考)。本文標題中雖然沒有明確指明”后 Kubernetes 時代的微服務“是什么,但是從文中可以看出作者的觀點是:在后 Kubernetes 時代,服務網格(Service Mesh)技術已完全取代了使用軟件庫實現網絡運維(例如 Hystrix 斷路器)的方式。本文索性就借用該標題。
本文中包含以下內容
說明 kube-proxy 的作用。
Kubernetes 在微服務管理上的局限性。
介紹下 Istio Service Mesh 的功能。
介紹下 xDS 包含哪些內容。
比較了 Kubernetes、Envoy 和 Istio Service Mesh 中的一些概念。
本文觀點
如果你沒有心里閱讀下文的所有內容,那么可以先閱讀看下下面列出的本文中的一些主要觀點:
Kubernetes 的本質是應用的生命周期管理,具體說是部署和管理(擴縮容、自動恢復、發布)。
Kubernetes 為微服務提供了可擴展、高彈性的部署和管理平臺。
Service Mesh 的基礎是透明代理,通過 sidecar proxy 攔截到微服務間流量后再通過控制平面配置管理微服務的行為。
Service Mesh 將流量管理從 Kubernetes 中解耦,Service Mesh 內部的流量無需 kube-proxy 組件的支持,通過為更接近微服務應用層的抽象,管理服務間的流量、安全性和可觀察性。
Envoy xDS 定義了 Service Mesh 配置的協議標準。
Service Mesh 是對 Kubernetes 中的 service 更上層的抽象,它的下一步是 serverless。
適用人群
本文假定您已經對 Kubernetes 有比較全面的了解,同時還使用過 Istio service mesh,但是對于 Kubernetes、Envoy 及 Istio 之間的關系不甚了解,及 Istio 如何使用 xDS 協議控制所有的 Sidecar 有濃厚的興趣,那么推薦您繼續閱讀。
閱讀本文之前
推薦大家在閱讀本文之前希望您對微服務、容器和 Kubernetes 有一定認識,如果您已經閱讀過以下幾篇文章將對您理解本文更有幫助,本文中也引用過了下面文章中的部分觀點。
深入解讀 Service Mesh 背后的技術細節 by 劉超
Istio流量管理實現機制深度解析 by 趙化冰
Service Mesh架構反思:數據平面和控制平面的界線該如何劃定?by 敖小劍
理解 Istio Service Mesh 中 Envoy 代理 Sidecar 注入及流量劫持 by 宋凈超
Service Mesh 深度學習系列——Istio源碼分析之pilot-agent模塊分析 by 丁軼群
為什么走到這一步
使用 Service Mesh 并不是說與 Kubernetes 決裂,而是水到渠成的事情。Kubernetes 的本質是通過聲明式配置對應用進行生命周期管理,而 Service Mesh 的本質是應用間的流量和安全性管理。假如你已經使用 Kubernetes 構建了穩定的微服務平臺,那么如何設置服務間調用的負載均衡和流量控制?
在閱讀本文前先問自己幾個問題
我想聽說過 Service Mesh 并試用過 Istio 的人可能都會有以下幾個疑問:
為什么 Istio 一定要綁定 Kubernetes 呢?
Kubernetes 和 Service Mesh 分別在云原生中扮演什么角色?
Istio 擴展了 Kubernetes 的哪些方面?解決了哪些問題?
Kubernetes、Envoy(xDS 協議)與 Istio 之間又是什么關系?
到底該不該上 Service Mesh?
為什么寫這篇文章
從 ServiceMesher 社區的反饋來看,很多初次接觸 Istio 和 Service Mesh 的同學,跟著那個 Istio 官方文檔可以迅速的搭建和試用 Istio 的各種功能,了解 Service Mesh 能為你做什么,但用戶所有的操作都僅是在控制平面完成的,至于 Istio 如何操作數據平面,即每個 Sidecar proxy 的呢?
Kubernetes 1.13 如期發布了,Kubernetes 依然按照四個月一個版本的速度迭代著,但是我們能看到的重大革新越來越少了,已經過了技術采納的初級階段,正在大規模落地,關于 Kubernetes 的書籍、演講已經扎堆,我不會過多得講到 Kubernetes。本文不一定能夠回答以上所有問題,本文僅為我個人理解,拋磚引玉。
注意:這篇文章中涉及大量的數據平面的細節。
Kubernetes vs Service Mesh
下圖展示的是 Kubernetes 與 Service Mesh 中的的服務訪問關系,本文僅針對 sidecar per-pod 模式,詳情請參考服務網格的實現模式。
Kubernetes 集群的每個節點都部署了一個 kube-proxy 組件,該組件會與 Kubernetes API Server 通信,獲取集群中的 service 信息,然后設置 iptables 規則,直接將對某個 service 的請求發送到對應的 Endpoint(屬于同一組 service 的 pod)上。
Istio Service Mesh 中沿用了 Kubernetes 中的 service 做服務注冊,通過 Control Plane 來生成數據平面的配置(使用 CRD 聲明,保存在 etcd 中),數據平面的透明代理(transparent proxy)以 sidecar 容器的形式部署在每個應用服務的 pod 中,這些 proxy 都需要請求 Control Plane 來同步代理配置,之所以說是透明代理,是因為應用程序容器完全無感知代理的存在,該過程 kube-proxy 組件一樣需要攔截流量,只不過 kube-proxy 攔截的是進出 Kubernetes 節點的流量,而 sidecar proxy 攔截的是進出該 Pod 的流量,詳見理解 Istio Service Mesh 中 Envoy Sidecar 代理的路由轉發。
Service Mesh 的劣勢
因為 Kubernetes 每個節點上都會運行眾多的 Pod,將原先 kube-proxy 方式的路由轉發功能置于每個 pod 中,這將導致大量的配置分發、同步和最終一致性問題。為了細粒度的機型流量管理,必將代理一系列新的抽象,增加了用戶的心智負擔,但隨著技術的普及慢慢將得到緩解。
Service Mesh 的優勢
kube-proxy 的設置都是全局生效的,無法對每個服務做細粒度的控制,而 Service Mesh 通過 sidecar proxy 的方式將 Kubernetes 中對流量的控制從 service 一層抽離出來,可以做更多的擴展。
kube-proxy 組件
在 Kubernetes 集群中,每個 Node 運行一個 kube-proxy 進程。kube-proxy 負責為 Service 實現了一種 VIP(虛擬 IP)的形式。 在 Kubernetes v1.0 版本,代理完全在 userspace 實現。Kubernetes v1.1 版本新增了 iptables 代理模式,但并不是默認的運行模式。從 Kubernetes v1.2 起,默認使用 iptables 代理。在 Kubernetes v1.8.0-beta.0 中,添加了 ipvs 代理模式。關于 kube-proxy 組件的更多介紹請參考 kubernetes 簡介:service 和 kube-proxy 原理 和 使用 IPVS 實現 Kubernetes 入口流量負載均衡。
kube-proxy 的缺陷
在上面的鏈接中作者指出了 kube-proxy 的不足之處:
首先,如果轉發的 pod 不能正常提供服務,它不會自動嘗試另一個 pod,當然這個可以通過 liveness probes 來解決。每個 pod 都有一個健康檢查的機制,當有 pod 健康狀況有問題時,kube-proxy 會刪除對應的轉發規則。另外,nodePort 類型的服務也無法添加 TLS 或者更復雜的報文路由機制。
Kube-proxy 實現了流量在 Kubernetes service 多個 pod 實例間的負載均衡,但是如何對這些 service 間的流量做細粒度的控制,比如按照百分比劃分流量到不同的應用版本(這些應用都屬于同一個 service,但位于不同的 deployment 上),做金絲雀發布(灰度發布)和藍綠發布?Kubernetes 社區給出了 使用 Deployment 做金絲雀發布的方法,該方法本質上就是通過修改 pod 的 label 來將不同的 pod 劃歸到 Deployment 的 Service 上。
Kubernetes Ingress vs Istio Gateway
Kubernetes 中的 Ingress 資源對象跟 Istio Service Mesh 中的 Gateway 的功能類似,都是負責集群南北流量(從集群外部進入集群內部的流量)。
kube-proxy 只能路由 Kubernetes 集群內部的流量,而我們知道 Kubernetes 集群的 Pod 位于 CNI 創建的外網絡中,集群外部是無法直接與其通信的,因此 Kubernetes 中創建了 ingress 這個資源對象,它由位于 Kubernetes 邊緣節點(這樣的節點可以是很多個也可以是一組)的 Ingress controller 驅動,負責管理南北向流量(從集群外部進入 Kubernetes 集群的流量),Ingress 必須對接各種個 Ingress Controller 才能使用,比如 nginx ingress controller、traefik。Ingress 只適用于 HTTP 流量,使用方式也很簡單,只能對 service、port、HTTP 路徑等有限字段匹配來路由流量,這導致它無法路由如 MySQL、redis 和各種私有 RPC 等 TCP 流量。要想直接路由南北向的流量,只能使用 Service 的 LoadBalancer 或 NodePort,前者需要云廠商支持而且可能需要付費,后者需要進行額外的端口管理。有些 Ingress controller 支持暴露 TCP 和 UDP 服務,但是只能使用 Service 來暴露,Ingress 本身是不支持的,例如 nginx ingress controller,服務的暴露的端口是通過創建 ConfigMap 的方式來配置的。
Istio Gateway 描述的負載均衡器用于承載進出網格邊緣的連接。該規范中描述了一系列開放端口和這些端口所使用的協議、負載均衡的 SNI 配置等內容。Gateway 是一種 CRD 擴展,它同時復用了 Envoy proxy 的能力,詳細配置請參考 Istio 官網。
xDS 協議
下面這張圖大家在了解 Service Mesh 的時候可能都看到過,每個方塊代表一個服務的示例,例如 Kubernetes 中的一個 Pod(其中包含了 sidecar proxy),xDS 協議控制了 Istio Service Mesh 中所有流量的具體行為,即將下圖中的方塊鏈接到了一起。
xDS 協議是由 Envoy 提出的,在 Envoy v2 版本 API 中最原始的 xDS 協議只指 CDS、EDS、LDS 和 RDS。
下面我們以兩個 service,每個 service 都有兩個實例的例子來看下 Envoy 的 xDS 協議。
上圖中的箭頭不是流量在進入 Enovy Proxy 后的路徑或路由,而是想象的一種 Envoy 中 xDS 接口處理的順序并非實際順序,其實 xDS 之間也是有交叉引用的。
Envoy 通過查詢文件或管理服務器來動態發現資源。概括地講,對應的發現服務及其相應的 API 被稱作
xDS 。Envoy 通過 訂閱( subscription )方式來獲取資源,訂閱方式有以下三種:文件訂閱:監控指定路徑下的文件,發現動態資源的最簡單方式就是將其保存于文件,并將路徑配置在 ConfigSource 中的 path 參數中。
gRPC 流式訂閱:每個 xDS API 可以單獨配置 ApiConfigSource,指向對應的上游管理服務器的集群地址。
輪詢 REST-JSON 輪詢訂閱:單個 xDS API 可對 REST 端點進行的同步(長)輪詢。
以上的 xDS 訂閱方式詳情請參考 xDS 協議解析。Istio 使用的 gRPC 流式訂閱的方式配置所有的數據平面的 sidecar proxy。
關于 xDS 協議的詳細分解請參考丁軼群博士的這幾篇文章:
Service Mesh深度學習系列part1—istio源碼分析之pilot-agent模塊分析
Service Mesh深度學習系列part2—istio源碼分析之pilot-discovery模塊分析
Service Mesh深度學習系列part3—istio源碼分析之pilot-discovery模塊分析(續)
文章中介紹了 Istio pilot 的總體架構、Envoy 配置的生成、pilot-discovery 模塊的功能,以及 xDS 協議中的 CDS、EDS 及 ADS,關于 ADS 詳情請參考 Enovy 官方文檔。
xDS 協議要點
最后總結下關于 xDS 協議的要點:
CDS、EDS、LDS、RDS 是最基礎的 xDS 協議,它們可以分別獨立更新的。
所有的發現服務(Discovery Service)可以連接不同的 Management Server,也就是說管理 xDS 的服務器可以是多個。
Envoy 在原始 xDS 協議的基礎上進行了一些列擴充,增加了 SDS(秘鑰發現服務)、ADS(聚合發現服務)、HDS(健康發現服務)、MS(Metric 服務)、RLS(速率限制服務)等 API。
為了保證數據一致性,若直接使用 xDS 原始 API 的話,需要保證這樣的順序更新:CDS --> EDS --> LDS --> RDS,這是遵循電子工程中的先合后斷(Make-Before-Break)原則,即在斷開原來的連接之前先建立好新的連接,應用在路由里就是為了防止設置了新的路由規則的時候卻無法發現上游集群而導致流量被丟棄的情況,類似于電路里的斷路。
CDS 設置 Service Mesh 中有哪些服務。
EDS 設置哪些實例(Endpoint)屬于這些服務(Cluster)。
LDS 設置實例上監聽的端口以配置路由。
RDS 最終服務間的路由關系,應該保證最后更新 RDS。
Envoy
Envoy 是 Istio Service Mesh 中默認的 Sidecar,Istio 在 Enovy 的基礎上按照 Envoy 的 xDS 協議擴展了其控制平面,在講到 Envoy xDS 協議之前還需要我們先熟悉下 Envoy 的基本術語。下面列舉了 Envoy 里的基本術語及其數據結構解析,關于 Envoy 的詳細介紹請參考 Envoy 官方文檔,至于 Envoy 在 Service Mesh(不僅限于 Istio) 中是如何作為轉發代理工作的請參考網易云劉超的這篇深入解讀 Service Mesh 背后的技術細節 以及理解 Istio Service Mesh 中 Envoy 代理 Sidecar 注入及流量劫持,本文引用其中的一些觀點,詳細內容不再贅述。
基本術語
下面是您應該了解的 Enovy 里的基本術語:
Downstream(下游):下游主機連接到 Envoy,發送請求并接收響應,即發送請求的主機。
Upstream(上游):上游主機接收來自 Envoy 的連接和請求,并返回響應,即接受請求的主機。
Listener(監聽器):監聽器是命名網地址(例如,端口、unix domain socket 等),下游客戶端可以連接這些監聽器。Envoy 暴露一個或者多個監聽器給下游主機連接。
Cluster(集群):集群是指 Envoy 連接的一組邏輯相同的上游主機。Envoy 通過服務發現來發現集群的成員。可以選擇通過主動健康檢查來確定集群成員的健康狀態。Envoy 通過負載均衡策略決定將請求路由到集群的哪個成員。
Envoy 中可以設置多個 Listener,每個 Listener 中又可以設置 filter chain(過濾器鏈表),而且過濾器是可擴展的,這樣就可以更方便我們操作流量的行為,例如設置加密、私有 RPC 等。
xDS 協議是由 Envoy 提出的,現在是 Istio 中默認的 sidecar proxy,但只要實現 xDS 協議理論上都是可以作為 Istio 中的 sidecar proxy 的,例如螞蟻金服開源的 SOFAMosn 和 nginx 開源的 nginmesh。
Istio Service Mesh
Istio 是一個功能十分豐富的 Service Mesh,它包括如下功能:
流量管理:這是 Istio 的最基本的功能。
策略控制:通過 Mixer 組件和各種適配器來實現,實現訪問控制系統、遙測捕獲、配額管理和計費等。
可觀測性:通過 Mixer 來實現。
安全認證:Citadel 組件做密鑰和證書管理。
Istio 中的流量管理
Istio 中定義了如下的 CRD 來幫助用戶進行流量管理:
Gateway:Gateway 描述了在網絡邊緣運行的負載均衡器,用于接收傳入或傳出的HTTP / TCP連接。
VirtualService:VirtualService 實際上將 Kubernetes 服務連接到 Istio Gateway。它還可以執行更多操作,例如定義一組流量路由規則,以便在主機被尋址時應用。
DestinationRule:DestinationRule 所定義的策略,決定了經過路由處理之后的流量的訪問策略。簡單的說就是定義流量如何路由。這些策略中可以定義負載均衡配置、連接池尺寸以及外部檢測(用于在負載均衡池中對不健康主機進行識別和驅逐)配置。
EnvoyFilter:EnvoyFilter 對象描述了針對代理服務的過濾器,這些過濾器可以定制由 Istio Pilot 生成的代理配置。這個配置初級用戶一般很少用到。
ServiceEntry:默認情況下 Istio Service Mesh 中的服務是無法發現 Mesh 外的服務的,ServiceEntry 能夠在 Istio 內部的服務注冊表中加入額外的條目,從而讓網格中自動發現的服務能夠訪問和路由到這些手工加入的服務。
Kubernetes vs Envoy xDS vs Istio
在閱讀完上文對 Kubernetes 的 kube-proxy 組件、Envoy xDS 和 Istio 中流量管理的抽象概念之后,下面將帶您僅就流量管理方面比較下三者對應的組件/協議(注意,三者不可以完全等同)。
| Endpoint | Endpoint | - |
| Service | Route | VirtualService |
| kube-proxy | Route | DestinationRule |
| kube-proxy | Listener | EnvoyFilter |
| Ingress | Listener | Gateway |
| Service | Cluster | ServiceEntry |
總結
如果說 Kubernetes 管理的對象是 Pod,那么 Service Mesh 中管理的對象就是一個個 Service,所以說使用 Kubernetes 管理微服務后再應用 Service Mesh 就是水到渠成了,如果連 Service 你也不像管了,那就用如 knative 這樣的 serverless 平臺,這就是后話了。
Envoy 的功能也不只是做流量轉發,以上概念只不過是 Istio 在 Kubernetes 之上新增一層抽象層中的冰山一角,但因為流量管理是服務網格最基礎也是最重要的功能,所以本文從這里開始,以后將給大家介紹更多關于服務網格的細節,請關注我的博客 jimmysong.io 和 istio-handbook。
參考
Istio 流量管理的基本概念詳解 - jimmysong.io
Kubernetes kube-proxy 中的 iptables 代理模式 - jimmysong.io
Kubernetes kube-proxy 中的 ipvs 代理模式 - jimmysong.io
Envoy v2 API 概覽 - servicemesher.com
監聽器發現服務(LDS)- servicemesher.com
路由發現服務(RDS)- servicemesher.com
集群發現服務(CDS)- servicemesher.com
Kubernetes service - jimmysong.io
xDS 協議解析 - jimmysong.io
深入解讀 Service Mesh 背后的技術細節 - cnblogs.com
理解 Istio Service Mesh 中 Envoy 代理 Sidecar 注入及流量劫持 - jimmysong.io
kubernetes 簡介:service 和 kube-proxy 原理 - cizixs.com
使用 IPVS 實現 Kubernetes 入口流量負載均衡 - jishu.io
Istio 流量管理實現機制深度解析 - zhaohuabing.com
企業級服務網格架構之路解讀 - jimmysong.io
調試 Envoy 和 Pilot - istio.io
總結
以上是生活随笔為你收集整理的Service Mesh(服务网格)——后 Kubernetes 时代的微服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: VisualNet地税管道资源管理系统
- 下一篇: python 显示字典内容_在pytho