Beyond Istio OSS —— Istio 服務網格的現狀及未來
關於本文
本文根據筆者在 GIAC 深圳 2022 年大會上的的演講 《Beyond Istio OSS —— Istio 的現狀及未來》 整理而成,演講幻燈片見 騰訊文件 。
本文回顧了 Istio 開源近五年來的發展,並展望了 Istio 服務網格的未來方向。本文的主要觀點如下:
- 因為 Kubernetes、微服務、DevOps 及雲原生架構的流行,導致服務網格技術的興起;
- Kubernetes 和可程式設計代理,為 Istio 的出現打下了堅實的基礎;
- 雖然 eBPF 可以加速 Istio 中的透明流量劫持,但無法取代服務網格中的 sidecar;
- Istio 的未來在於構建基於混合雲的零信任網路;
Istio 誕生的前夜
2013 年起,隨著移動網際網路的爆發,企業對應用迭代的效率要求更高,應用程式架構開始從單體轉向微服務,DevOps 也開始變得流行。同年隨著 Docker 的開源,解決了應用封裝和隔離的問題,使得應用在編排系統中排程變得更容易。2014 年 Kubernetes、Spring Boot 開源,Spring 框架開發微服務應用開始流行,在接下來的幾年間大批的 RPC 中介軟體開源專案出現,如 Google 在 2016 年釋出 gRPC 1.0,螞蟻在 2018 年開源 SOFAStack 等,微服務框架百花齊放。為了節約成本,增加開發效率,使應用更具彈性,越來越多的企業正在遷移上雲,但這不僅僅是將應用搬到雲上那麼簡單,為了更高效地利用雲端計算,一套「雲原生」方法和理念也呼之欲出。
Istio 開源時間線
Istio 開源發展時間線如下圖所示。
下面我們來簡單回顧下 Istio 開源大事件:
- 2016 年 9 月:因為 Envoy 是 Istio 中的重要組成,Istio 的開源時間線應該有 Envoy 一部分。起初 Envoy 在 Lyft 內部僅作為邊緣代理,開源前已在 Lyft 內部得到大規模生產驗證並受到了 Google 工程師的注意,那時候 Google 正打算推出一個服務網格的開源專案。2017 年,Lyft 將 Envoy 捐獻給了 CNCF 。
- 2017 年 5 月:Istio 由 Google、IBM 和 Lyft 聯合宣佈開源。一開始就使用了微服務架構,確定了資料平面和控制平面的組成以及 Sidecar 模式。
- 2018 年 3 月:Kubernetes 順利的成為從 CNCF 中第一個畢業的專案,變得越來越「無聊」,基礎 API 已經定型,CNCF 正式將服務網格(Service Mesh)寫入到了雲原生的第二版定義中。筆者當前就職的公司 Tetrate ,也是在那時由 Google Istio 初創團隊創業成立的。服務網格在中國開始爆發,ServiceMesher 社群也在螞蟻集團的支援下成立,在中國佈道服務網格技術。
- 2018 年 7 月:Istio 1.0 釋出,號稱「生產可用」,Istio 團隊重組。
- 2020 年 3 月:Istio 1.5 釋出,架構迴歸單體,釋出週期確定,每三個月釋出一個大版本,API 趨於穩定。
- 2020 年至今:Istio 的發展主要著重於 Day 2 Operation、效能優化和擴充套件性發面,多個圍繞 Istio 生態的開源專案開始出現,例如 Slime 、 Areaki 、 Merbridge 。
為什麼 Istio 會在 Kubernetes 之後出現?
微服務和容器化之後,異構語言使用的增加,服務的數量激增,容器的生命週期變短是導致服務網格出現的根本原因。
我們先來看下服務從部署在 Kubernetes 到 Istio 中架構的變遷,然後再探討架構演進過程中 Istio 的需求,下文假定讀者已瞭解Kubernetes 和 Istio 的架構 。
從 Kubernetes 到 Istio,概括的講應用的部署架構有如下特點:
-
Kubernetes 管理應用的生命週期,具體來說,就是應用的部署和管理(擴縮容、自動恢復、釋出策略);
-
基於 Kubernetes 的自動 sidecar 注入,實現了透明流量攔截。先通過 sidecar 代理攔截到微服務間流量,再通過控制平面配置管理微服務的行為。如今服務網格的部署模式也迎來了新的挑戰,sidecar 已經不是 Istio 服務網格所必須的,基於 gRPC 的無代理的服務網格也在測試中。
-
服務網格將流量管理從 Kubernetes 中解耦,服務網格內部的流量無須
kube-proxy
元件的支援, 通過類似於微服務應用層的抽象,管理服務間的流量,實現安全性和可觀察性功能。 -
Kubernetes 叢集外部的客戶端訪問叢集內部服務時,原先是通過 KubernetesIngress ,在有了 Istio 之後,會通過 Gateway 來訪問。
Kubernetes 容器編排與可程式設計代理 Envoy 為 Istio 的出現打下了堅實的基礎。
從上面 Kubernetes 到 Istio 的架構的轉變的描述中,我們可以看到為了讓開發者最小成本地管理服務間的流量,Istio 需要解決三個問題:
- 透明劫持應用間的流量 :Istio 開源最初的目標是成為網路基礎設施,就像水和電人類的基礎設施一樣,我們使用水電不需要關心如何取水和發電,只需要開啟水龍頭,按下開關即可。透明流量劫持對於開發者來說,就像使用水和電,不需要修改應用程式就可以快速使用 Istio 帶來的流量管理能力;
- 代理叢集的運維 :如何為每個應用注入一個代理,同時高效地管理這些分散式的 sidecar 代理;
- 可程式設計代理 :代理可以通過 API 動態配置,還要有出色的效能與可擴充套件性;
以上三個條件對於 Istio 服務網格來說缺一不可,而且,從中我們可以看到,這些要求基本都是對於 sidecar 代理的要求,這個代理的選擇將直接影響該專案的走向與成敗。為了解決以上三個問題,Istio 選擇了 Kubernetes 容器編排和可程式設計代理 Envoy。
透明流量劫持
如果你使用的是如 gRPC 這類中介軟體開發微服務,在程式中整合 SDK 後,SDK 中的攔截器會自動為你攔截流量,如下圖所示。
如何讓 Kubernetes pod 中的流量都通過代理呢?答案是在每個應用程式 pod 中注入一個代理,與應用共享網路空間,再通過修改 pod 內的流量路徑,讓所有進出 pod 的流量都經過 sidecar,其架構如下圖所示。
從圖中我們可以看到其中有一套非常複雜的 iptables 流量劫持邏輯(詳見 Istio 中的 Sidecar 注入、透明流量劫持及流量路由過程詳解 ),使用 iptables 的好處是適用於任何 Linux 作業系統。但是這也帶來了一些副作用:
- Istio 網格中所有的服務都需要在進出 pod 時都增加了一個網路跳躍點(hop),雖然每次 hop 可能只有兩三毫秒,但是隨著網格中服務和服務間的依賴增加,這種延遲可能會顯著增加,對於那種追求低延遲的服務可能就不適用於服務網格了;
- 因為 Istio 向資料平面中注入了大量的 sidecar,尤其是當服務數量增大時,控制平面需要下發更多的 Envoy 代理配置到資料平面,這樣會使資料平面佔用大量的系統記憶體和網路資源;
針對這兩個問題,如何優化服務網格呢?
- 使用 proxyless 模式:取消 sidecar 代理,重新回到 SDK;
- 優化資料平面:減少下發到資料平面的配置的頻率和大小;
- eBPF:使用 eBPF 優化網路劫持;
本文將在後面一節講解這些細節。
Sidecar 運維管理
Istio 是在 Kubernetes 的基礎上構建的,它可以利用 Kubernetes 的容器編排和生命週期管理,在 Kubernetes 建立 pod 時,通過准入控制器自動向 pod 中注入 sidecar。
為了解決 Sidecar 的資源消耗問題,有人為服務網格提出了有四種部署模式,如下圖所示。
下表中詳細對比了這四種部署方式,它們各有優劣,具體選擇哪種根據實際情況而定。
模式 | 記憶體開銷 | 安全性 | 故障域 | 運維 |
---|---|---|---|---|
Sidecar 代理 | 因為為每個 pod 都注入一個代理,所以開銷最大。 | 由於 sidecar 必須與工作負載一起部署,工作負載有可能繞過 sidecar。 | Pod 級別隔離,如果有代理出現故障,隻影響到 Pod 中的工作負載。 | 可以單獨升級某個工作負載的 sidecar 而不影響其他工作負載。 |
節點共享代理 | 每個節點上只有一個代理,為該節點上的所有工作負載所共享,開銷小。 | 對加密內容和私鑰的管理存在安全隱患。 | 節點級別隔離,如果共享代理升級時出現版本衝突、配置衝突或擴充套件不相容等問題,則可能會影響該節點上的所有工作負載。 | 不需要考慮注入 Sidecar 的問題。 |
Service Account / 節點共享代理 | 服務賬戶 / 身份下的所有工作負載都使用共享代理,開銷小。 | 工作負載和代理之間的連線的認證及安全性無法保障。 | 節點和服務賬號之間級別隔離,故障同 “節點共享代理”。 | 同 “節點共享代理”。 |
帶有微代理的共享遠端代理 | 因為為每個 pod 都注入一個微代理,開銷比較大。 | 微代理專門處理 mTLS,不負責 L7 路由,可以保障安全性。 | 當需要應用 7 層策略時,工作負載例項的流量會被重定向到 L7 代理上,若不需要,則可以直接繞過。該 L7 代理可以採用共享節點代理、每個服務賬戶代理,或者遠端代理的方式執行。 | 同 “Sidecar 代理”。 |
可程式設計代理
Flomesh 的張曉輝曾在 為什麼需要可程式設計代理 部落格中詳細說明了代理軟體的發展演化過程,我下面將引用他的一些觀點,說明可程式設計代理 Envoy 在 Istio 中的關鍵作用。
下圖展示了代理從配置到可程式設計模式的演化過程,及每個階段中的代表性代理軟體。
整個代理演化過程都是隨著應用從本地和單體,越來越走向大規模和分散式。下面我將簡要概括代理軟體的發展過程:
- 配置檔案時代 :幾乎所有軟體都有配置檔案,代理軟體因為其相對複雜的功能,更離不開配置檔案。該階段的代理主要使用 C 語言開發,包括其擴充套件模組,突出的代理本身的能力。這也是我們使用代理最原始最基礎的形式,這些代理包括 Nginx、Apache HTTP Server、 Squid 等;
- 配置語言時代 :這個時代的代理,更具擴充套件性和靈活性,比如動態資料獲取和配套的邏輯判斷。代表性代理包括擴 Varnish 和 HAProxy;
- 指令碼語言時代 :從指令碼語言的引入開始,代理軟體才真正走向的可程式設計,我們可以更方便的使用指令碼在代理中增加動態邏輯,增加了開發效率。代表性的代理是 Nginx 及其支援的指令碼語言;
- 叢集時代 :隨著雲端計算的普及,大規模部署和動態配置 API 成了代理所必需的能力,而且隨著網路流量的增加,大規模代理叢集也應運而生。這個時代的代表性代理有 Envoy、Kong 等;
- 雲原生時代 :多租戶、彈性、異構混合雲、多叢集、安全和可觀測,這些都是雲原生時代對代理所提出的更高要求,代表性軟體有 Istio、Linkerd、 Pypi ,它們都為代理構建了控制平面。
這些都是服務網格嗎?
現在我將列舉一些流行的服務網格開源專案,讓我們一起探索服務網格的發展規律和本質。下表對比了當前流行的服務網格開源專案。
對比項 | Istio | Linkerd | Consul Connect | Traefik Mesh | Kuma | Open Service Mesh (OSM) |
---|---|---|---|---|---|---|
當前版本 | 1.14 | 2.11 | 1.12 | 1.4 | 1.5 | 1.0 |
許可證 | Apache License 2.0 | Apache License 2.0 | Mozilla License | Apache License 2.0 | Apache License 2.0 | Apache License 2.0 |
發起者 | Google、IBM、Lyft | Buoyant | HashiCorp | Traefik Labs | Kong | Microsoft |
服務代理 | Envoy,支援 gRPC 的 proxyless 模式 | Linkerd2-proxy | 預設為 Envoy ,可替換 | Traefik Proxy | Envoy | Envoy |
入口控制器 | Envoy,自定義的 Ingress,支援 Kubernetes Gateway API | 無內建 | Envoy,支援 Kubernetes Gateway API | 無內建 | Kong | 支援 Contour、Nginx,相容其他 |
治理 | Istio Community 和 Open Usage Commons,已提議捐獻給 CNCF | CNCF | 檢視 貢獻指南 | 檢視 貢獻指南 | CNCF | CNCF |
上表中列出的都是服務網格,下面再簡單評論一下這些專案:
- Istio :目前最流行的服務網格專案之一,在中國幾乎成為了服務網格的代名詞;
- Linkerd :最早出現的服務網格,「Service Mesh」概念提出者,第一個進入 CNCF 的服務網格專案,使用自研的 Rust 語言編寫輕量級 sidecar 代理;
- Traefik Mesh :由 Traefik 推出的服務網格專案,使用 Treafik proxy 作為 sidecar,支援 SMI(接下來會提到),它的特點是對應用的無侵入性,不會在 pod 中注入 sidecar;
- Kuma :由 Kong 推出的服務網格專案,使用 Envoy 作為 Sidecar 代理,特色是使用 Kong 自家的閘道器作為入口閘道器;
- Consul Connect :Consul 服務網格,使用 Envoy 作為 sidecar 代理;
- Open Service Mesh :由微軟開源的服務網格,使用 Envoy 作為 sidecar,相容 SMI(同樣是微軟提出);
另外還有幾個專案,也服務網格領域也經常被提及,但它們都不是服務網格:
- Envoy :Envoy 本身只是代理,也經常被作為其他基於 Envoy 的服務網格的 sidecar,也經常被用來構建 API Gateway;
- Service Mesh Performance(SMP) :標準化了服務網格值的指標,通過捕獲基礎設施容量、服務網格配置和工作負載元資料的細節來描述任何部署的效能;
- Service Mesh Interface(SMI) :它不是服務網格,而只是一套服務網格實現標準,與 OAM、SPIFFE、CNI、CSI 等類似都是定義介面標準,具體實現就不一而足了。目前 Traefik Mesh 和 Open Service Mesh 宣告支援該規範;
- Network Service Mesh :有必要提一下這個專案,因為經常有人把它錯認為是一個服務網格。實際上,它面向的是三層網路,使用它可以在不更換 CNI 外掛的前提下,連線多雲/混合雲。它並不是我們所定義的「服務網格」,而是服務網格的一個有力補充(雖然名字裡帶有服務網格比較有迷惑性)。
縱觀以上專案,我們可以看出大部分服務網格專案的發起者都是根據代理起家,然後做控制平面。而且 Istio、Consul Connect、Open Service Mesh、Kuma 都是使用 Envoy 作為 sidecar 代理。只有 Linkerd 和 Traefik Mesh 推出了自己的代理。而所有的服務網格專案都支援 sidecar 模式。除了 Istio、Linkerd、Consul Connect 已應用於生產上,其他服務網格專案還沒有看到被大規模在生產上使用。
Istio 的效能優化
在 Istio 1.5 版本確定了穩定的架構之後,社群的主要精力在於優化 Istio 的效能。下面我將向你詳細介紹 Istio 中的效能優化方法,包括:
- 採用 Proxyless 模式;
- 使用 eBPF 優化流量劫持;
- 控制平面效能優化;
- 資料平面效能優化;
Proxyless 模式
Proxyless 模式是 Istio 在 1.11 版本中提出的實驗特性 —— 基於 gRPC 和 Istio 的無 sidecar 代理的服務網格 。使用該模式可以直接將 gRPC 服務新增到 Istio 中,而不需要再向 Pod 中注入 Envoy 代理。下圖展示了 sidecar 模式與 proxyless 模式的對比圖。
從上圖中我們可以看到,雖然 proxyless 模式不使用 proxy 進行資料平面通訊,但仍然需要一個 agent(即 pilot-agent
) 來進行初始化和與控制平面的通訊。首先,agent 在啟動時生成一個 引導檔案
,與為 Envoy 生成引導檔案的方式相同。這告訴 gRPC 庫如何連線到 istiod
,在哪裡可以找到用於資料平面通訊的證書,向控制平面傳送什麼元資料。接下來,agent 作為 xDS proxy,代表應用程式與 istiod
進行連線和認證。最後,agent 獲取並輪換資料平面通訊中使用的證書,這其實與 Sidecar 模式的流程是一樣的,只是將 Envoy 代理的功能內建到 SDK 中了。
服務網格的本質不是 Sidecar 模式,也不是配置中心或透明流量攔截,而是標準化的服務間通訊標準。
有人說 proxyless 模式又回到了基於 SDK 開發微服務的老路,服務網格的優勢喪失殆盡,那還能叫做服務網格嗎?其實這也是一種對效能的妥協 —— 如果你主要使用 gRPC 來開發微服務的話,只需要維護不同語言的 gRPC 版本,即可以通過控制平面來管理微服務了。
Envoy xDS 已經成為服務網格中服務間通訊的事實標準。
使用 eBPF 優化流量劫持
在一節,我們可以看到一個服務間的流量在到達目的地 pod 時經過的 iptables 規則和路徑,其中需要經過多條 iptables 規則,如 PREROUTING
、 ISTIO_INBOUND
、 ISTIO_IN_REDIRECT
、 OUTPUT
、 ISTIO_OUTPUT
、 POSTROUTING
等。假設現在有一個服務 A 想要呼叫非本地主機上的另一個 pod 中的服務 B,經過的網路堆疊如下圖所示。
從圖中我們可以看到整個呼叫流程中經過四次 iptables,其中 Pod A 中的從 Envoy 的出站(iptables2)和 Pod B 中的從 eth0 的入站(iptables3)的 iptables 路由是無法避免的,那麼剩下的兩個 iptables1 和 iptables4 是否可以優化呢?讓兩個 socket 直接通訊,不就可以縮短網路路徑了嗎?這就需要通過 eBPF 程式設計,使得:
- Service A 的流量從直接傳送到 Envoy 的 Inbound socket 上;
- Pod B 中 Envoy 接收到入站流量後,已經確定流量是要傳送給本地的服務,直接對接 Outbound socket 與 Service B;
使用 eBPF 模式的透明流量攔截網路路徑如下圖所示。
如果要訪問的服務 A 和服務 B 在同一個節點上,那麼網路路徑將更短。
同一個節點中的服務間訪問完全繞過了 TCP/IP 堆疊,變成了 socket 間的直接訪問。
什麼是 eBPF?
我們知道修改 Linux 核心程式碼很難,新特性發布到核心中需要很長的週期。eBPF 是一個框架,允許使用者在作業系統的核心內載入和執行自定義程式。也就是說,有了 eBPF,你不需要直接修改核心,就可以擴充套件和改變核心的行為。下面我將簡要的為大家介紹一下 eBPF:
- eBPF 程式載入到核心中後需要通過驗證器的驗證才可以執行,驗證器可以防止 eBPF 程式超越許可權的訪問,這樣可以確保核心的安全;
- eBPF 程式是附著於核心事件上的,當有進入或退出核心函式時被觸發;
- 核心空間的 eBPF 程式必須使用能夠支援生成 eBPF 位元組碼格式的編譯器的語言編寫,目前你可以用 C 和 Rust 語言編寫 eBPF 程式;
- eBPF 程式對於不同的 Linux 版本存在相容性問題;
由於 eBPF 程式可以直接監聽和操作 Linux 核心,具有對系統最底層的透視,就可以在流量管理、可觀測性和安全發揮作用。有關 eBPF 的詳細介紹請參考筆者翻譯的《什麼是 eBPF》 電子書。
開源專案 Merbridge 正是利用 eBPF 縮短了透明流量劫持的路徑,優化了服務網格的效能。關於 Merbridge 實現的一些細節,請參考 Istio 部落格 。
注意
Merbridge 使用的 eBPF 函式需要 Linux 核心版本 ≥ 5.7。
乍看上去 eBPF 似乎從更底層實現了 Istio 的功能,更大有取代 sidecar 的趨勢。但是 eBPF 也存在很多侷限性,導致在可以預見的未來無法取代服務網格和 Sidecar。如果取消 sidecar 轉而使用每個主機一個代理的模式,會導致:
- 代理失敗的爆炸半徑擴大到整個節點,即一個代理失敗了,代理所在節點上的所有工作負載都會受到影響;
- 使得安全問題更加複雜,因為一個節點上儲存在太多負載的證書,一旦被攻擊,會存在祕鑰洩露的風險;
- 主機上的 Pod 之間的流量爭搶問題,即節點上如果有一個工作負載消耗掉代理的所有資源,其他工作負載將無法獲得流量;
而且 eBPF 主要負責三/四層流量,可以與 CNI 一起執行,但是七層流量使用 eBPF 來處理就不太合適了。
在可以預見的未來 eBPF 技術無法取代服務網格和 Sidecar。
關於 eBPF 與服務網格的關係的更詳細介紹請參考部落格 請暫時拋棄使用 eBPF 取代服務網格和 Sidecar 模式的幻想 。
控制平面效能優化
以上兩種優化都是針對資料平面進行的,我們再來看下控制平面的效能優化。你可以把服務網格想象成是一場演出,控制平面是總導演,資料平面是所有演員,導演不參與演出,但是負責指揮演員。如果這場演出的情節很簡單,時長又很短,那要每個演員分配的戲份就會很少,排練起來就會很容易;如果是一個大型演出,演員的數量多,情節有很複雜,要想排練好這場演出,一個導演可能是不夠的,他指揮不了這麼多演員,因此我們需要多名副導演(擴大控制平面例項數量);我們還需要給演員準備好臺詞和指令碼,如果演員也可以一個鏡頭完成一連串的臺詞和場景的表演(減少都資料平面的打擾,批量推送更新),那我們的排練是不是更加高效?
從上面的類比中,你應該可以找到控制平面效能優化的方向了,那就是:
- 減少需要推送的配置大小;
- 批處理代理推送;
- 擴大控制平面規模;
減少需要推送的配置
控制平面效能優化最直接的方式就是減少要向資料平面推送的代理配置大小。假設有工作負載 A,如果僅將與 A 相關的代理配置(即 A 依賴的服務)推送給 A,而不是將網格內所有服務的配置都推送給 A,這樣就可以大大壓縮要推送的工作負載範圍及配置大小。Istio 中的 Sidecar 資源可以幫助我們實現這一點。下面是 Sidecar 配置示例:
apiVersion: networking.istio.io/v1alpha3 kind: Sidecar metadata: name: default namespace: cn-bj spec: workloadSelector: labels: app: app-a egress: - hosts: - "cn-bj/*"
我們通過 workloadSelector
欄位可以限制該 Sidecar 配置適用的工作負載範圍,而 egress
欄位可以確定該工作負載依賴的服務範圍,這樣控制平面就可以僅向服務 A 推送其依賴的服務配置,大大減低要向資料平面推送的配置大小,減少了服務網格的記憶體和網路消耗。
批處理代理配置推送
控制平面 Istiod 向資料平面推送代理配置的過程比較複雜,下圖展示了其中的流程。
管理員配置 Istio 網格後,Istiod 中推送代理配置的流程是這樣的:
DiscoveryServer
從以上流程中我們可以看出,優化配置推送的關鍵就是步驟 2 中去抖動週期和步驟 4 中的限流設定。有這樣幾個環境變數可以幫助你設定控制平面的推送:
PILOT_DEBOUNCE_AFTER PILOT_DEBOUNCE_MAX PILOT_ENABLE_EDS_DEBOUNCE PILOT_PUSH_THROTTLE
關於這些環境變數的預設值和具體配置請參考 Istio 文件 。
這些值究竟如何設定,可以遵循以下原則:
-
如果控制平面資源空閒,為了加快配置更新的傳播速度,你可以:
- 縮短去抖動週期,增加推送次數;
- 增加同時處理的推送請求數量;
-
如果控制平面飽和,為了降低效能瓶頸,你可以:
- 延遲去抖動週期,減少推送次數;
- 增加同時處理的推送請求的數量;
至於如何設定最優解,需要結合你的可觀測系統來除錯。
擴大控制平面規模
如果設定去抖動批處理和 Sidecar 還無法優化控制平面效能的話,最後的選擇就是擴大控制平面的規模,包括擴大單個 Istiod 例項的資源和增加 Istiod 的例項個數,究竟採用哪種擴充套件方式視情況而定:
- 當單個 Istiod 的資源佔用飽和時,優先推薦你擴大 Istiod 的例項大小,這通常是因為服務網格中有太多的資源(Istio 的自定義資源,如 VirtualService、DestinationRule 等)需要處理;
- 如果增加 Istiod 例項的 CPU 和記憶體依然不起效的話,增加 Istiod 的例項個數,這樣可以分散單個例項要管理的工作負載數量;
資料平面效能優化
Apache SkyWalking 可以作為 Istio 提供可觀測性工具,還可以幫助我們在進行服務動態除錯和故障排除剖析服務的效能,其最新推出的 Apache SkyWalking Rover 元件可以利用 eBPF 技術來準確定位 Istio 的關鍵效能問題。在資料平面,我們可以通過以下方式來增加 Envoy 的吞吐量以優化 Istio 的效能:
- 禁用 Zipkin 追蹤或減少採樣率
- 簡化訪問日誌格式
- 禁用 Envoy 的訪問日誌服務(ALS)
以上優化方式對 Envoy 吞吐量的影響資料請參閱 使用 eBPF 準確定位服務網格的關鍵效能問題 。
Envoy —— 服務網格的領銜主演
我們知道服務網格是由資料平面和控制平面組成的,從上面的服務網格開源專案列表中我們可以看到,服務網格開源專案大部分都是基於 Envoy,然後開發自己的控制平面。還記得我在本文前面將服務網格比作演出嗎?在這場服務網格的演出中,毫無疑問 Envoy 就是領銜主演 —— Envoy 發明的 xDS 協議,基本成為服務網格的通用 API。下面展示的是 Envoy 的架構圖。
xDS 是 Envoy 區別於其他代理的關鍵,它的程式碼和解析流程十分複雜,直接擴充套件起來也很有難度。下面展示的是 Istio 元件拓撲圖,從圖中我們可以看到 Istio 資料平面的 Sidecar 容器中不止有 envoy
這一個程序,還有一個 pilot-agent
程序。
pilot-agent
程序的作用如下:
envoy
從以上功能中我們可以看出 pilot-agent
程序主要是用於與 Istiod 互動,為 Envoy 起到指揮和輔助的作用,Istio 的核心元件是 Envoy。那麼 Envoy 會不會「演而優則導」,不再配合 Istio,構建一套自己的控制平面呢?
在 Sidecar 容器中, pilot-agent
就像是 Envoy 的 “Sidecar”。
請讀者思考一下
pilot-agent
的功能能否直接內建到 Envoy 中,從而取消 pilot-agent
呢?
Envoy Gateway 統一服務網格閘道器
在 Kubernetes 中,除 Service 資源物件之外,最早用來暴露叢集中服務的資源物件是 Ingress。使用 Ingress 你只需要為叢集開放一個對外的訪問點即可,通過 HTTP Hosts 和 path
來路由流量到具體的服務。相對於直接在 service
資源上暴露服務來說,可以減少叢集的網路訪問點(PEP),降低叢集被網路攻擊的風險。使用 Ingress 訪問叢集內的服務流程如下圖所示。
在 Kubernetes 之前,API Gateway 軟體就已經被廣泛用作邊緣路由了,在引用 Istio 時又增加了 Istio 自定義的 Gateway 資源,使得訪問 Istio 服務網格中的資源又多了一種選擇,如下圖所示。
現在,要想暴露單個 Istio 網格中的服務, NodePort
、 LoadBalance
、Istio 自定義 Gateway、Kubernetes Ingress 和 API Gateway 軟體,如何選擇?如果是多叢集服務網格,客戶端如何訪問網格內的服務?我們的服務網格領銜主演 Envoy 已經在這方面做足了功夫,被以多種形式使用:
- Sidecar Proxy:正如在提到的,Istio、Kuma、Consul Connect 都使用了 Envoy 作為 sidecar 代理;
- Kubernetes Ingress Controller/API Gateway: Contour 、 Emissary 、 Hango 、 Gloo 等;
這些專案利用 Envoy 來實現服務網格和 API 閘道器,其中有很多功能重疊,同時又有很多專有功能,或者缺乏社群多樣性,這種現狀由於 Envoy 社群沒有提供控制平面實現而導致的。為了改變現狀,Envoy 社群發起了 Envoy Gateway 專案,該專案旨在結合現有的基於 Envoy 的 API Gateway 相關專案的經驗,利用帶有一些 Envoy 特定擴充套件的 Kubernetes Gateway API 降低 Envoy 使用者使用閘道器的門檻。因為 Envoy Gateway 仍然通過 xDS 下發配置給 Envoy 代理,因此你還可以用它來管理支援 xDS 的閘道器,如 Istio Gateway。
我們現在所見的閘道器基本都是在單叢集中作為入口閘道器,對於多叢集和多網格就無能為力了。為了應對多叢集,我們需要在 Istio 之上再新增一層閘道器,和一個全域性的控制平面以在多叢集間路由流量,如下圖所示。
關於兩級閘道器的簡要介紹
- 一級閘道器(下文簡稱 T1)位於應用邊緣,用於多叢集環境。同一應用會同時託管在不同的叢集上,T1 閘道器將對該應用的請求流量在這些叢集之間路由。
- 二級閘道器(下文簡稱 T2)位於一個的叢集邊緣,用於將流量路由到該叢集內由服務網格管理的服務。
通過在 Istio 控制平面以外增加一層全域性控制平面和 API,來實現多叢集服務網格管理。將 T1 閘道器部署為叢集,可以防止單點故障。想要了解關於兩級閘道器的更多內容,請參考 通過兩級閘道器設計來路由服務網格流量 。
T1 閘道器的配置如下所示:
apiVersion: gateway.tsb.tetrate.io/v2 kind: Tier1Gateway metadata: name: service1-tier1 group: demo-gw-group organization: demo-org tenant: demo-tenant workspace: demo-ws spec: workloadSelector: namespace: t1 labels: app: gateway-t1 istio: ingressgateway externalServers: - name: service1 hostname: servicea.example.com port: 80 tls: {} clusters: - name: cluster1 weight: 75 - name: cluster2 weight: 25
該配置將 servicea.example.com
通過 T1 閘道器暴露到網格外,並將網格外訪問該服務的流量的 75%
轉發到 cluster1
, 25%
的流量轉發到 cluster2
,另外為了應對多叢集中的流量、服務和安全配置,Tetrate 旗艦產品 Tetrate Service Bridge 中還增加了 一系列 Group API,詳見 TSB 文件
。
Istio 開源生態
Istio 開源在至今已經五年多了,近兩年來出現了很多基於 Istio 的開源專案,其中比較代表性的有:
- 網易開源的 Slime
- 騰訊開源的 Aeraki
- Istio 官方對 Wasm 外掛的支援
它們的出現使得 Istio 更加智慧化並擴充套件了 Istio 的適用範圍。
Slime
Slime 是由網易數帆微服務團隊開源的一款基於 Istio 的智慧網格管理器。Slime 基於 Kubernetes Operator 實現,可作為 Istio 的 CRD 管理器,無須對 Istio 做任何定製化改造,就可以定義動態的服務治理策略,從而達到自動便捷使用 Istio 和 Envoy 高階功能的目的。
我們在前文的中提到了通過「減少需要推送的配置」的方式來優化 Istio 的效能,但是 Istio 無法做到自動識別無法依賴以最優化需要推送到每個 sidecar 的代理配置,Slime 提供了 lazyload
控制器,可以幫助我們實現配置懶載入,使用者無須手動配置 SidecarScope
,Istio 可以按需載入服務配置和服務發現資訊。
下圖展示的是 Slime 作為 Istio 的管理平面更新資料平面配置的流程圖。
其中,Global Proxy 使用 Envoy 構建,在每個需要啟動配置懶載入的名稱空間中部署一個或在整個網格中只部署一個,所有缺失服務發現資訊的呼叫(你也可以手動配置服務呼叫關係),都會被兜底路由劫持到 Global Proxy,經過其首次轉發後,Slime 便可感知到被呼叫方的資訊,然後根據其對應服務的 VirtualService,找到服務名和真實後端的對映關係,將兩者的都加入 SidecarScope,以後該服務的呼叫就不再需要經過 Global Proxy 了。
資料平面配置更新的具體步驟如下:
- Slime Operator 根據管理員的配置在 Kubernetes 中完成 Slime 元件的初始化,開發者建立符合 Slime CRD 規範的配置並應用到 Kubernetes 叢集中;
- Slime 持續監聽 Slime CRD 的建立;
- Slime 查詢 Prometheus 中儲存的相關服務的監控資料,結合 Slime CRD 中自適應部分的配置,將 Slime CRD 轉換為 Istio CRD,同時將其推送到 Global Proxy 中;
- Istio 監聽 Istio CRD 的建立;
- Istio 將代理的配置資訊推送到資料平面相應的 Sidecar Proxy 中;
因為資料平面中的所有服務的首次呼叫都通過 Global Proxy,該 Proxy 可以記錄所有服務的呼叫和依賴資訊,根據該依賴資訊更新 Istio 中 Sidecar 資源的配置;當某個服務的呼叫鏈被 VirtualService 中的路由資訊重新定義時, Global Proxy 原有記錄就失效了,需要一個新的資料結構來維護該服務的呼叫關係。Slime 建立了名為 ServiceFence
的 CRD 來維護服務呼叫關係以解決服務資訊缺失問題,詳見Slime 簡介 。
Aeraki
Aeraki Mesh 是騰訊雲在 2021 年 3 月開源的一個服務網格領域的專案,基於 Istio 擴充套件其對七層協議的支援,專注於解決 Istio 中的 非 HTTP 協議 的服務治理,已於 2022 年 6 月進入 CNCF Sandbox。
下圖展示了 Aeraki 將非 HTTP 協議納入到 Istio 網格中的流程圖。
其詳細流程如下:
tcp-metaprotocol-dubbo
在 Istio 中接入非 HTTP 服務的整個流程中的關鍵是 MetaProtocol Proxy 。Istio 預設支援 HTTP/HTTP2、TCP 和 gRPC 協議,實驗性支援 Mongo、MySQL 和 Redis 協議。若要使用 Istio 路由其他協議的流量,不僅需要修改 Istio 控制平面並擴充套件 Envoy,這將帶來巨大的工作量,而且不同協議共享通用的控制邏輯,這還會帶來很多重複性工作。MetaProtocol Proxy 是在 Envoy 程式碼基礎上的擴充套件,為七層協議統一實現了服務發現、負載均衡、RDS 動態路由、流量映象、故障注入、本地/全侷限流等基礎能力,大大降低了在 Envoy 上開發第三方協議的難度。
下圖展示的 MetaProtocol Proxy 的架構圖。
當我們想擴充套件 Istio 使其支援 Kafka、Dubbo、Thrift 等其他七層協議時,只需要實現上圖中的編解碼的介面(Decode 和 Encode),就可以基於 MetaProtocol 快速開發一個第三方協議外掛。MetaProtocol Proxy 是在 Envoy 基礎上的擴充套件,因此你仍然可以使用多種語言為其開發過濾器,並使用 EnvoyFilter
資源將配置下發到資料平面。
WasmPlugin API
WasmPlugin 是 Istio 1.12 版本引入的 API,作為代理擴充套件機制,我們可以使用它將自定義和第三方的 Wasm 模組新增到資料平面中。下圖中展示瞭如何在 Istio 中使用 WasmPlugin。
具體步驟如下:
- 使用者使用 Proxy-Wasm SDK (目前有 AssemblyScript、C++、Rust、Zig 和 Go 語言版本)來開發擴充套件,並構建成 OCI 映象(如 Docker 映象)上傳到映象倉庫;
-
使用者編寫
WasmPlugin
配置並應用到 Istio; -
Istio 控制平面根據
WasmPlugin
配置中的工作負載選擇配置,將 Wasm 模組注入到指定的 Pod 中; -
Sidecar 中的
pilot-agent
從遠端或本地檔案中獲取 Wasm 模組並將其載入到 Envoy 中執行;
誰應該使用 Istio?
好了,說了這麼說,這跟你有什麼關係呢?Istio 跟你的關係取決於你的角色:
- 如果你是平臺負責人,應用服務網格後,可能增強你的平臺可觀測性,具有了一個統一的平臺來管理微服務,你將是直接受益者,也應該是服務網格的主要實施者;
- 如果是應用程式開發者,也會從服務網格中收益,因為你可以更加專屬於業務邏輯,而不用擔心重試策略、TLS 等其他非功能性問題;
下圖展示了服務網格的採用路徑。
是否採用服務網格取決於你公司的技術發展階段,應用是否實現容器化和微服務,對多語言的需求,是否需要 mTLS 以及對效能損耗的接納度等。
服務網格在雲原生技術棧中的定位
技術的發展日新月異,近兩年來有一些新技術出現,似乎挑戰了服務網格的地位,更有人聲稱可以直接取代現有經典的 sidecar 模式的服務網格,我們不要被外界嘈雜的聲音所迷惑,認清服務網格在雲原生技術棧中的定位。
一味地推廣某項技術而忽略它的適用場景,就是耍流氓。
下圖展示的是雲原生技術堆疊。
我們可以看到,在雲原生技術堆疊圖中的「雲基礎設施」、「中介軟體」和「應用」層都列舉了一些標誌性的開源專案,這些專案構建了它們所在領域的標準:
- 在雲基礎設施領域,Kubernetes 統一了容器編排和應用生命週期管理的標準,Operator 模式奠定了擴充套件 Kubernetes API 及第三方應用接入的標準;
- 在中介軟體領域,服務網格承擔起了雲原生技術棧中的七層網路、可觀測性和安全等多個方面的部分或全部責任,它執行在應用程式下層,對於應用程式來說幾乎是無感知的;Dapr(分散式應用程式執行時)定義雲原生中介軟體的能力模型,開發者可以在應用中整合 Dapr 的多語言 SDK,面向 Dapr 提供的分散式能力程式設計,而不用關心應用所執行的環境及對接的後端基礎設施。因為在和應用程式執行在同一個 Pod 中的 Dapr 執行時(Sidecar 模式部署,其中包含各種構建塊)自動幫我們對接了後端元件(Component);
- 在應用程式領域:OAM 旨在建立一個應用模型標準,通過元件、特徵、策略和工作流來一個應用程式,詳見雲原生資料庫 ;
下圖展示了 Istio 在雲原生部署中定位於七層網格管理。
Dapr 與 Istio 是什麼關係?
在雲原生技術棧中,Istio 和 Dapr 同時位於中介軟體層,它們之間有很多區別和聯絡。
Istio 和 Dapr 之間的相同點:
- Istio 和 Dapr 都可以使用 Sidecar 模式的部署模型;
- 同屬於中介軟體,同樣可以管理服務間通訊;
Istio 和 Dapr 之間的不同點:
- 目標不同:Istio 的目標是構建零信任網路,定義服務間通訊標準,Dapr 目標是構建標準的中介軟體能力的 API;
- 架構不同:Istio = Envoy + 透明流量劫持 + 控制平面,Dapr = 多語言 SDK + 標準化 API + 分散式能力元件;
- 面向的人群不同:但是應用 Istio 對於開發者來說幾乎無感知,主要需要基礎設施運維團隊實施,而應用 Dapr 需要開發者自主選擇整合 Dapr SDK;
服務網格的未來
我在前文中介紹了 Istio 的發展脈絡及開源生態,接下來我將為大家介紹 Istio 服務網格的未來趨勢:
- 構建零信任網路
- 成為混合雲管理平臺的網路基礎設施
服務網格的未來在於成為零信任網路和混合雲的基礎設施。
這也是筆者所在的公司企業級服務網格提供商 Tetrate 的努力方向,我們致力於構建一個基於零信任的適用於任意環境、任意負載的應用感知網路。下面展示的是 Tetrate 旗艦產品 Tetrate Service Bridge 的架構圖。
Tetrate 公司是由 Istio 專案的發起人創立的,TSB 是基於開源的 Istio、Envoy 和 Apache SkyWalking 開發的。我們同時積極得貢獻上游社群,並參與了旨在簡化將 Envoy 閘道器使用的 Envoy Gateway 專案的建立(上圖中的 XCP 即使用 Envoy 構建的閘道器)。
零信任
零信任(Zero Trust)是 IstioCon 2022 裡的一個重要話題,Istio 正在成為零信任網路的一個重要組成部分。
什麼是零信任?
零信任(Zero Trust)是一種安全理念,而不是一種所有安全團隊都要遵循的最佳實踐。零信任概念的提出是為了給雲原生世界帶來更安全的網路。零信任是一種理論狀態,即網路內的所有消費者不僅沒有任何許可權,而且也不具備對周圍網路的感知。零信任的主要挑戰是就越來越細化的授權和和對使用者授權的時間限制。關於更多零信任的介紹,請閱讀這篇部落格 。
身份認證
零信任網路中最重要的是 面向身份的控制 而不是面向網路的控制。Istio 1.14 中增加了對 SPIRE 的支援,SPIRE(SPIFFE Runtime Environment,CNCF 孵化專案) 是 SPIFFE(Secure Production Identity Framework For Everyone,CNCF 孵化專案) 的一個實現。在 Kubernetes 中我們使用ServiceAccount 為 Pod 中的工作負載提供身份資訊,其核心是基於 Token(使用 Secret 資源儲存)來表示負載身份。而 Token 是 Kubernetes 叢集中的資源,對於多叢集及執行在非 Kubernetes 環境(例如虛擬機器)中的負載,如何統一它們的身份?這就是 SPIFFE 要解決的問題。
SPIFFE 的目的是基於零信任的理念,建立一個開放、統一的工作負載身份標準,這有助於建立一個零信任的全面身份化的資料中心網路。SPIFFE 的核心是通過簡單 API 定義了一個生命週期短暫的加密身份檔案—— SVID(SPFFE Verifiable Identity Document),用作工作負載認證時使用的身份檔案(基於 X.509 證書或 JWT 令牌)。SPIRE 可以根據管理員定義的策略自動輪換 SVID 證書和祕鑰,動態地提供工作負載標識,同時 Istio 可以通過 SPIRE 動態的消費這些工作負載標識。
基於 Kubernetes 的 SPIRE 架構圖如下所示。
Istio 中原先是使用 Istiod 中 Citadel 服務負責服務網格中證書管理,通過 xDS(準確的說是 SDS API)協議將證書下發給資料平面。有了 SPIRE 之後,證書管理的工作就交給了 SPIRE Server。SPIRE 同樣支援 Envoy SDS API,我們在 Istio 中啟用 SPIRE 之後,進入工作負載 Pod 中的流量在被透明攔截到 Sidecar 中後,會經過一次身份認證。身份認證的目的是對比該工作負載的身份,與它所執行的環境資訊(所在的節點、Pod 的 ServiceAccount 和 Namespace 等)是否一致,以防止偽造身份。請參考 如何在 Istio 中整合 SPIRE 以瞭解如何在 Istio 中使用 SPIRE 做身份認證。
我們可以使用 Kubernetes Workload Registrar 在 Kubernetes 中部署 SPIRE,它會為我們自動註冊 Kubernetes 中的工作負載並生成 SVID。該註冊機是 Server-Agent 架構,它在每個 Node 上部署一個 SPIRE Agent,Agent 與工作負載通過共享的 UNIX Domain Socket 通訊。零信任網路中每個流量會話都需要經過身份認證,Istio 在透明流量劫持時,Sidecar 同時對流量請求進行身份認證。下圖展示了在 Istio 中使用 SPIRE 進行身份認證的過程。
Istio 中使用 SPIRE 進行工作負載認證的步驟如下:
pilot-agent
關於工作負載的註冊和認證的詳細過程請參考SPIRE 文件 。
NGAC
當每個工作負載都有準確的身份之後,如何對這些身份的許可權進行限制?Kubernetes 中預設使用 RBAC 來做訪問控制,正如其名,這種訪問控制是基於角色的,雖然使用起來比較簡單,但是對於大規模叢集,存在角色爆炸問題 —— 即存在太多角色,而且角色的型別不是一成不變的,難以對角色許可權機型跟蹤和審計。另外 RBAC 中的角色的訪問許可權是固定,沒有規定短暫的使用許可權,也沒有考慮位置、時間或裝置等屬性。使用 RBAC 的企業很難滿足複雜的訪問控制要求,以滿足其他組織需求的監管要求。
NGAC,即下一代訪問控制,採用將訪問決定資料建模為DAG (有向無環圖)的方法。NGAC 可以實現系統化、策略一致的訪問控制方法,以高精細度授予或拒絕使用者管理能力。NGAC 由 NIST (美國國家標準與技術研究所)開發,目前已用於 Tetrate Service Bridge 中的許可權管理。關於為什麼選擇 NGAC,而不是 ABAC 和 RBAC 的更多內容請參考部落格 為什麼應該選擇使用 NGAC 作為許可權控制模型 。
混合雲
在實際應用中,我們可能出於負載均衡、隔離開發和生產環境、解耦資料處理和資料儲存、跨雲備份和災難恢復以及避免廠商鎖定等原因,在多種環境下部署多個 Kubernetes 叢集。Kubernetes 社群提供了「叢集聯邦」功能可以幫助我們建立多叢集架構,例如下圖所示的一種常用的 Kubernetes 多叢集架構,其中 Host Cluster 作為控制平面,有兩個成員叢集,分別是 West 和 East。
叢集聯邦要求 Host 叢集與成員叢集的之間的網路能夠互通,對成員叢集之間的網路連線性沒有要求。Host 叢集作為 API 入口,外界所有對 Host 叢集的資源請求會轉發到成員叢集中。Host 叢集中部署有叢集聯邦的控制平面,其中的 「Push Reconciler」會將聯邦中的身份、角色及角色繫結傳播到所有的成員叢集中。叢集聯邦只是簡單地將多個叢集簡單的「連線到了一起」,在多個叢集之間複製工作負載,而成員叢集之間的流量無法排程,也無法實現真正的多租戶。
叢集聯邦不足以實現混合雲,為了實現真正意義上的混合雲,就要讓叢集之間做到互聯互通,同時實現多租戶。TSB 在 Istio 之上構建一個多叢集管理的通用控制平面,然後再增加一個管理平面來管理多叢集,提供多租戶、管理配置、可觀察性等功能。下面是 Istio 管理平面的多租戶和 API 示意圖。
TSB 為管理混合雲,基於 Istio 構建了一個管理平面,新建了 Tenant 和 Workspace 的資源,並通過選擇器,將閘道器組、流量組和安全組應用到對應叢集中的工作負載上。關於 TSB 的詳細架構請參考 TSB 文件 。
更多
如果你想了解更多關於 Istio 和雲原生的內容,下面有一些資料分享給你:
- 為了幫助大家更好的瞭解 Istio 和雲原生,筆者在 2020 年發起了 雲原生社群 ,歡迎大家加入我們一起探索後 Kubernetes 時代的雲原生新正規化;
- 2022 年 6 月,雲原生社群著的 《深入理解 Istio —— 雲原生服務網格進階實戰》 已圖書由電子工業出版社出版,歡迎大家購買;
- 筆者於 2022 年 5 月,將之前所作電子書、教程和譯文全部遷移到了雲原生資料庫 ,歡迎閱讀和留言評論。
參考
- 自 2020 年以來全球的開源商業化軟體融資情況
- IstioCon 2022 回顧及錄影、PPT 分享
- Beyond Istio OSS —— Istio 服務網格的現狀及未來
- 如何在 Istio 中整合 SPRIRE?
- 什麼是零信任?
- 為什麼 Istio 要使用 SPIRE 做身份認證?
- 再見 KataCoda!
- 如何編譯 Istio?
- Istio 資料平面 Pod 啟動過程詳解
- Istio 中的各元件埠及功能詳解
- Istio sidecar 中的流量型別及 iptables 規則詳解
- Tetrate 公司開源專案介紹
- 跨越鴻溝:理解鴻溝理論
- 網易開源 Istio 擴充套件專案 Slime 簡介——基於 Istio 的智慧服務網格管理器
- 服務網格現狀之我見
- 如何理解 Istio Ingress, 它與 API Gateway 有什麼區別?
- 如何除錯 Kubernetes 中的微服務 ——proxy、sidecar 還是 service mesh?
- Jimmy Song:為什麼山寨幣持有者不關心比特幣 Taproot 升級?
- Zoom OBS B 站直播配置手冊
- Istio 開源四週年回顧與展望