天天看點

Service Mesh——後 Kubernetes 時代的微服務

本文是以前所寫内容的重新修訂并收錄于 ServiceMesher 社群的 Istio Handbook

中,其他章節仍在編纂中。

剛聽說 Service Mesh 并試用過

Istio 的人可能都會有下面幾個疑問:

  1. 為什麼 Istio 要綁定 Kubernetes 呢?
  2. Kubernetes 和 Service Mesh 分别在雲原生中扮演什麼角色?
  3. Istio 擴充了 Kubernetes 的哪些方面?解決了哪些問題?
  4. Kubernetes、xDS 協定( Envoy MOSN 等)與 Istio 之間又是什麼關系?
  5. 到底該不該上 Service Mesh?

這一節我們将試圖帶您梳理清楚 Kubernetes、xDS 協定以及 Istio Service Mesh 之間的内在聯系。此外,本節還将介紹 Kubernetes 中的負載均衡方式,xDS 協定對于 Service Mesh 的意義以及為什麼說及時有了 Kubernetes 還需要 Istio。

使用 Service Mesh 并不是說與 Kubernetes 決裂,而是水到渠成的事情。Kubernetes 的本質是通過聲明式配置對應用進行生命周期管理,而 Service Mesh 的本質是提供應用間的流量和安全性管理以及可觀察性。假如你已經使用 Kubernetes 建構了穩定的微服務平台,那麼如何設定服務間調用的負載均衡和流量控制?

Envoy 創造的 xDS 協定被衆多開源軟體所支援,如

Linkerd

等。Envoy 對于 Service Mesh 或雲原生來說最大的貢獻就是定義了 xDS,Envoy 本質上是一個 proxy,是可通過 API 配置的現代版 proxy,基于它衍生出來很多不同的使用場景,如 API Gateway、Service Mesh 中的 Sidecar proxy 和邊緣代理。

本節包含以下内容

  • 說明 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

    元件的支援,通過為更接近微服務應用層的抽象,管理服務間的流量、安全性和可觀察性。
  • xDS 定義了 Service Mesh 配置的協定标準。
  • Service Mesh 是對 Kubernetes 中的 service 更上層的抽象,它的下一步是 serverless。

Kubernetes vs Service Mesh

下圖展示的是 Kubernetes 與 Service Mesh 中的的服務通路關系(每個 pod 一個 sidecar 的模式)。

流量轉發

Kubernetes 叢集的每個節點都部署了一個

kube-proxy

元件,該元件會與 Kubernetes API Server 通信,擷取叢集中的

service

資訊,然後設定 iptables 規則,直接将對某個 service 的請求發送到對應的 Endpoint(屬于同一組 service 的 pod)上。

服務發現

Istio Service Mesh 可以沿用了 Kubernetes 中的 service 做服務注冊,還可以通過控制平面的平台擴充卡對接其他服務發現系統,然後生成資料平面的配置(使用 CRD 聲明,儲存在 etcd 中),資料平面的透明代理(transparent proxy)以 sidecar 容器的形式部署在每個應用服務的 pod 中,這些 proxy 都需要請求控制平面來同步代理配置。之是以說是透明代理,是因為應用程式容器完全無感覺代理的存在,該過程 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

上文說到

kube-proxy

隻能路由 Kubernetes 叢集内部的流量,而我們知道 Kubernetes 叢集的 Pod 位于

CNI

建立的外網絡中,叢集外部是無法直接與其通信的,是以 Kubernetes 中建立了

ingress

這個資源對象,它由位于 Kubernetes

邊緣節點

(這樣的節點可以是很多個也可以是一組)的 Ingress controller 驅動,負責管理南北向流量,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 本身是不支援的,例如

,服務暴露的端口是通過建立 ConfigMap 的方式來配置的。

Istio Gateway 的功能與 Kubernetes Ingress 類似,都是負責叢集的南北向流量。Istio

Gateway

描述的負載均衡器用于承載進出網格邊緣的連接配接。該規範中描述了一系列開放端口和這些端口所使用的協定、負載均衡的 SNI 配置等内容。Gateway 是一種

CRD 擴充

,它同時複用了 sidecar proxy 的能力,詳細配置請參考

Istio 官網

xDS 協定

下面這張圖大家在了解 Service Mesh 的時候可能都看到過,每個方塊代表一個服務的執行個體,例如 Kubernetes 中的一個 Pod(其中包含了 sidecar proxy),xDS 協定控制了 Istio Service Mesh 中所有流量的具體行為,即将下圖中的方塊連結到了一起。

xDS 協定是由

提出的,在 Envoy v2 版本 API 中最原始的 xDS 協定指的是 CDS(Cluster Discovery Service)、EDS(Endpoint Discovery service)、LDS(Listener Discovery Service) 和 RDS(Route Discovery Service),後來在 v3 版本中又發展出了 Scoped Route Discovery Service(SRDS)、Virtual Host Discovery Service (VHDS)、Secret Discovery Service(SDS)、Runtime Discovery Service(RTDS)詳見

xDS REST and gRPC protocol

下面我們以各有兩個執行個體的 service,來看下 xDS 協定。

上圖中的箭頭不是流量進入 Proxy 後的路徑或路由,也不是實際順序,而是想象的一種 xDS 接口處理順序,其實 xDS 之間也是有交叉引用的。

支援 xDS 協定的代理通過查詢檔案或管理伺服器來動态發現資源。概括地講,對應的發現服務及其相應的 API 被稱作 xDS。Envoy 通過訂閱(subscription)方式來擷取資源,訂閱方式有以下三種:

  • 檔案訂閱:監控指定路徑下的檔案,發現動态資源的最簡單方式就是将其儲存于檔案,并将路徑配置在 ConfigSource 中的

    path

    參數中。
  • gRPC 流式訂閱:每個 xDS API 可以單獨配置

    ApiConfigSource

    ,指向對應的上遊管理伺服器的叢集位址。
  • 輪詢 REST-JSON 輪詢訂閱:單個 xDS API 可對 REST 端點進行的同步(長)輪詢。

以上的 xDS 訂閱方式詳情請參考

xDS 協定解析

。Istio 使用 gRPC 流式訂閱的方式配置所有的資料平面的 sidecar proxy。

文章中介紹了 Istio pilot 的總體架構、proxy 配置的生成、pilot-discovery 子產品的功能,以及 xDS 協定中的 CDS、EDS 及 ADS,關于 ADS 詳情請參考

Envoy 官方文檔

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 是 Istio Service Mesh 中預設的 Sidecar,Istio 在 Enovy 的基礎上按照 Envoy 的 xDS 協定擴充了其控制平面,在講到 Envoy xDS 協定之前我們還需要先熟悉下 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 的,例如螞蟻金服開源的

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 xDS vs Istio

在閱讀完上文對 Kubernetes 的

kube-proxy

元件、xDS 和 Istio 中流量管理的抽象概念之後,下面将帶您僅就流量管理方面比較下三者對應的元件/協定(注意,三者不可以完全等同)。

Kubernetes xDS
Endpoint -
Service Route
kube-proxy DestinationRule
Listener EnvoyFilter
Ingress
Cluster ServiceEntry

總結

如果說 Kubernetes 管理的對象是 Pod,那麼 Service Mesh 中管理的對象就是一個個 Service,是以說使用 Kubernetes 管理微服務後再應用 Service Mesh 就是水到渠成了,如果連 Service 你也不想管了,那就用如

knative

這樣的 serverless 平台,但這就是後話了。

Envoy/MOSN 的功能也不隻是做流量轉發,以上概念隻不過是 Istio 在 Kubernetes 之上新增一層抽象層中的冰山一角,但因為流量管理是服務網格最基礎也是最重要的功能,是以這将成為本書的開始。

參考

繼續閱讀