1. 程式人生 > >採用輕量ServiceMesh實現灰度釋出的實踐

採用輕量ServiceMesh實現灰度釋出的實踐

軟體總會有缺陷的,解決問題的同時往往會引入新的問題,關鍵是看這些問題是否在我們的控制範圍內,“灰度釋出”就是讓問題受控的方法之一。


   前言   

我們的 CTO 經常說:“研發團隊最首要的任務是提供穩定的服務,然後才是提供符合客戶需求的、易用和低成本的產品”。但事實是,在提供穩定雲服務的同時,面對快速發展的客戶業務場景,我們還需要不斷 “擁抱變化”。 Max Kanat-Alexander 在《簡約之美:軟體設計之道》(Code Simplicity)中提出的軟體設計的 6 條法則恰到好處的描述了這一矛盾的事實,具體內容如下:

  1. 軟體的目的是幫助他人;

  2. 相比降低開發成本,更重要的是降低維護成本;

  3. 變化定律:軟體存在的時間越久,它的某部分需要變化的可能性越大;

  4. 缺陷定律:軟體出現缺陷的可能性,正比於你對它所做修改的程度;

  5. 簡潔定律:軟體任一部分的維護難度,正比於該部分的複雜程度;

  6. 測試定律:你對軟體行為的瞭解程度,等於你真正測試它的程度。

正像法則 1、3、4 和 6 所說的軟體的目的就是滿足客戶的需求,而隨著時間的推移,使用者需求總會改變;伴隨著使用者需求的改變,軟體也需要適應新的需求而做修改,修改必然會引入缺陷;如果要排除缺陷就必須進行測試。

但目前軟體行業的現狀大部分面臨這樣的問題,即無論花多大的成本去測試,真正的使用者行為背後的需求總是不可能被完全滿足的,缺陷總是會有的,這時我們最後的安全網就是“灰度釋出”(又名“金絲雀釋出”)。在採用使用者真實行為作為終極測試的同時,通過控制變更範圍儘可能的減少風險;一旦真的有缺陷可以快速回滾,儘可能以最大程度降低影響。

為何採用 ServiceMesh 實現灰度釋出

Service Mesh 是用來處理各服務間通訊的基礎設施層。它主要通過構建雲原生應用程式的各種複雜拓撲結構來完成傳遞請求。實際上,Service Mesh 通常與應用程式程式碼一起部署輕量級網路代理的陣列來實現請求。

在 ServiceMesh 之前,我們已經採用了 APIGateway 來實現灰度釋出,但 APIGateway 通常僅部署在使用者流量的入口,完全灰度釋出就需要完整地部署兩套系統。但是在微服務時代,任何一個微服務發生變更都需要完整地部署兩套系統,這不僅成本很高而且嚴重影響了產品變更的速度。

而 ServiceMesh 正好可以解決這些問題,它的應用類似於將 APIGateway 部署到本地,同時提供了集中化控制,極大地簡化了灰度釋出的實現流程、降低了變更成本、同時加快了產品釋出的進度。

為何採用輕量 ServiceMesh

正如敖小劍在《DreamMesh 拋磚引玉》系列文章中提到的:“Service Mesh 的發展程序,當前還處於前景雖然一致看好,但是腳下的路還處於需要一步一步走的早期艱難階段。由於 Istio 和 Conduit 的尚未成熟,造成目前 Service Mesh 青黃不接的尷尬局面。” 到底該如何讓 ServiceMesh 落地,這也是我們在 2017 年 10 月選擇了 ServiceMesh 之後面臨的難題。

Istio 可以提供一個完整的解決方案,通過為整個服務網格(ServiceMesh)提供行為檢測和操作控制來滿足微服務應用程式的各種需求。它在服務網路中提供了許多關鍵功能例如:流量管理、可觀察性、策略執行、服務身份和安全、平臺支援、整合和定製。

事實上我對 Istio 的流量管理 DSL 非常滿意,同時通過評測也能夠接受 Envoy 的效能開銷,從當時來看 Istio 確實是一個非常優秀的且是唯一的候選者。但敖小劍在《DreamMesh 拋磚引玉》描述的幾個問題,也困擾著我是否採用 Istio:

1. Ready forCloud Native?

我們目前並沒有採用 K8S,事實上我們所開發的 IaaS 控制面程式,本身就和 K8S 的功能類似。

2. 如何從非 Service Mesh 體系過渡到 Service Mesh?

我們有大量既有的服務。

3. 零侵入的代價

K8S 的網路方案已經是非常複雜且效能堪憂了,再通過 IPTables 來透明引流確實是雪上加霜,給未來的運維、Trouble-Shooting 帶來了很高的複雜度。

4. 網路通訊方案

目前我們主要使用 gRPC 和 HTTP,但仍有資料庫服務等業務不適合跑在 K8S 中,而 K8S 的網路方案需要能夠相容現有的資料庫等業務。

如何實現輕量 ServiceMesh

Istio 在邏輯上可以分為資料面板和控制面板,這兩部分的具體功能如下:

  • 資料面板由一組智慧代理(Envoy)組成,代理部署為 sidecar,調解和控制微服務之間所有的網路通訊。

  • 控制面板負責管理和配置代理來路由流量,以及在執行時執行策略。

下圖是構成每個面板的不同元件:

經過一些程式碼級別的 Research 之後,我們最終選擇了將 Pilot 從 Istio 中剝離出來,脫離 K8S 執行的輕量級 ServiceMesh 方案。

從 Istio 中剝離 Pilot 和 Envoy

在 Istio 中 Pilot 作為 Envoy 的控制面板提供集中式流量管理功能的模組,這是實現灰度釋出必不可少的功能,事實上也是 ServiceMesh 的核心功能。Mixer 提供訪問策略和控制功能,Istio-Auth 提供安全認證功能,但在 UCloud 的內網環境下,我們可以將這兩個模組去掉。

得益於 Pilot 的良好設計, ETCD Platform 很容易實現,進而從 ETCD 獲取 Service 和 ServiceInstance 資訊。然後我們重寫了 Pilot 的 main.go,保留了 Pilot 的 model、proxy 和 proxy/envoy 模組 ; 刪除其他的 Platform 僅保留新增的 ETCD Platform。最後我們在保留完整的 Istio DSL 支援的同時,得到了完全脫離 K8S 執行和編譯的 Pilot。

同時我們將 Pilot 和 ETCD gRPC naming and discovery 做了深度整合,自動剔除沒有線上的 ServiceInstance 資訊。

採用 docker-compose 管理 container 實現 sidecar

我們仍然採用 container 的方式打包和部署微服務,但採用 Host 的網路方式簡化了現存服務的網路通訊方式。為了實現 Envoy 的 sidecar 部署,我們採用 docker-compose 模擬 k8s 的 POD,管理服務間的依賴關係。通過實現一個簡單的服務管理、版本管理、叢集管理、路由策略管理層,為叢集中的每臺 Node(VM 或物理伺服器)生成 docker-compose 配置檔案,從而實現每臺 Node 的服務部署和管理。

最後針對 HTTP 1.0、HTTP 2.0 和 gRPC 的 RPC 方式,採用顯式代理而不是 IPTables 透明引流和 Envoy 整合。

  • 如果服務中配置了 Envoy 的 Proxy Port,則通過 Envoy 接入 ServiceMesh;

  • 如果配置是 IP 地址和埠,則直連這個地址;

  • 如果配置的是域名且沒有配置 Envoy 的 Proxy,則自動採用 ETCD gRPC naming and discovery 的方式去發現遠端服務。

   總結   

通過一系列的設計改造,最終我們得到了一個輕量的 ServiceMesh 實踐,實現了優化灰度釋出的目標。在保證了更好的控制變更範圍的同時,也能以提供更穩定的服務為最終目的。


作者簡介

徐亮 ,畢業於上海大學通訊與資訊工程學院,先後任職於上海貝爾、騰訊,有超過 18 年電信與網際網路行業研發管理經驗。2015 年加入 UCloud,主要負責雲平臺網路架構,包括 UXR 網路解耦、網路產品架構升級、虛擬網路架構升級等。