Ambassador是由Datawire開源的一個API網關項目,主要在Kubernetes的容器編排框架中使用。Ambassador本質上是一個通過配置邊緣/API來管理Envoy數據面板的控制面板。而Envoy則是一個基于第7層協議的網絡代理和通信總線,它是一個由Lyft開源的云原生服務,主要用于處理入口邊緣以及內部服務之間的網絡通信。今天Envoy正迅速成為現代網絡事實上的代理,幾乎所有的公共云供應商,以及eBay、Pinterest和Groupon等大型互聯網公司都提供對這種代理服務的支持。
本文首先介紹了Ambassador的由來,然后詳細介紹了它的發展過程,并討論了開發人員在構建這個控制面板時遇到的技術挑戰和經驗教訓,該面板用于在Kubernetes集群里管理微服務應用的入口流量(入口邊緣)。
本文要點:
Ambassador是由Datawire開源的一個API網關,主要在Kubernetes容器編排框架中使用。
Ambassador本質上是一個通過配置邊緣/API來管理Envoy代理數據面板的控制面板。
Envoy是一個處理邊緣入口和內部服務之間網絡通信的L7代理和通信總線。
本文介紹了Ambassador的由來,然后詳細介紹了它的發展過程,并討論了開發人員在構建這個控制面板時遇到的技術挑戰和經驗教訓,該面板用于管理部署到Kubernetes集群中的基于微服務的應用程序中的入口流量。
將Ambassador遷移到Envoyv2配置和ADS(聚合發現服務) API是一個漫長而艱難的過程,需要大量的架構和設計討論,以及大量的編碼,但是社區的早期反饋是積極的。
Ambassador是由Datawire開源的一個API網關項目,主要在Kubernetes的容器編排框架中使用。Ambassador本質上是一個通過配置邊緣/API來管理Envoy數據面板的控制面板。而Envoy則是一個基于第7層協議的網絡代理和通信總線,它是一個由Lyft開源的云原生服務,主要用于處理入口邊緣以及內部服務之間的網絡通信。今天Envoy正迅速成為現代網絡事實上的代理,幾乎所有的公有云供應商,以及eBay、Pinterest和Groupon等大型互聯網公司都提供對這種代理服務的支持。
本文首先介紹了Ambassador的由來,然后詳細介紹了它的發展過程,并討論了開發人員在構建這個控制面板時遇到的技術挑戰和經驗教訓,該面板主要用于在Kubernetes集群里管理微服務應用的入口流量。
云原生新興組合: Kubernetes與Envoy
像DevOps和微服務一樣,云原生也開始變得耳熟能詳,并在整個IT行業中不斷獲得關注。據Gartner報道,2018年全球公共云服務收入預計在1750億美元左右,而明年仍將有超過15%的增長。目前的公有云市場完全由幾家大公司壟斷,而這幾家公司也幾乎把持了所有的關鍵技術,這讓開源即服務的商業前景變得很不明朗。在這樣的背景下,Linux基金會于2015年成立了CNCF(云原生計算基金會),旨在討論和托管全棧云原生環境中的開源組件。
CNCF吸取了Open Stack社區的經驗教訓,在早期項目發展中相對保守和嚴格,它甚至為項目提供了發展概要,并要求項目有實際的應用案例,或者項目本身是基于已流行項目(如Kubernetes)的擴展。Google提供的Kubernetes容器編排框架,以及Lyft提供的邊緣路由器Envoy代理是CNCF早期的兩個主要項目。雖然平臺即服務(Platform-as-a-Service,PaaS)架構復雜且各不相同, 但Kubernetes和Envoy一直是其核心組成。
許多PaaS供應商,甚至最終用戶的技術團隊,都將針對網絡第7層元數據的編排容器和通信路由視為云原生系統的數據面板,比如HTTP URI、Headers以及MongoDB協議元數據。因此,更多的初創公司則把重心放在如何創建一個有效的\u0026quot;控制面板\u0026quot;上,例如幫助終端用戶實現與數據面板的交互,配置數據面板的自定義參數,觀察數據面板中的監測或日志等。
Kubernetes控制面板一般都采用了類似REST的API(又稱\u0026quot;Kubernetes API\u0026quot;),像‘kubectl‘這樣的CLI工具都是對此類API的二次封裝。首版Envoy的控制面板主要使用了JSON的配置方式,還有一些可以選擇性更新的松耦合API。隨后這些API又變成了Envoy v2 API的一部分,新版Envoy同時提供了一系列基于gRPC的協議緩沖類型API。最初Kubernetes的kubectl工具并沒有提供一種類似Envoy的實現,這給后來使用Kubernetes的團隊制造了不少麻煩。當然很多關于實現Envoy V2控制面板的初創公司也因此出現。
服務網格 VS API網關
談到網絡中的控制面板,自然就少不了新興的服務網格技術。諸如lstio、Linkerd和Conser connect之類的服務網格,主要在微服務系統中管理服務之間的通信,也就是所謂的“東-西”方向通信。lstio本身是一個非常有效的控制面板,它通過Envoy代理來管理網格之間的數據面板(L7網絡流量);Rust語言編寫的Linkerd實現了自己的代理;而Conser Connect則使用了自定義代理,最近也提供了對Envoy代理的支持。
服務網格需要事先假定用戶對網格通信的雙方具有高度的所有權和可控制度。例如,同一個公司的不同工程部門的兩個服務,或者是一個可信任網絡邊界內的第三方應用程序服務(可能跨越多個數據中心或虛擬專有云)。在這里,運維團隊通常會設置一些符合常理的通信缺省值,而服務團隊則在此基礎上配置各自服務間的路由。在這種情況下,你不可能完全信任每個服務,因此要實施如速率限制和斷路等保護,以此來調查和改變所檢測到的不良行為,但是服務網格根本不可能實現這類保護,因為邊緣或入口(“南-北”)流量來自外界網絡,超出了其控制范疇。
任何來自我們信任的網絡之外的通信都可能來自一個心懷不軌的的第三方,他的動機可能就是網絡罪犯或破壞移動應用程序中的客戶端庫,因此我們必須對邊緣/API網關部署適當的防御措施。在這里,運維團隊將指定一些系統默認值,并根據外部事件實時調整這些值。你可能希望能夠實現速率限制、全局配置和指定API負載(例如后端服務或數據集過載),以及DDoS保護實現等(基于時間或區域的保護)。另外,服務開發團隊的一些任務也需要訪問為新API配置路由的邊緣,通過流量跟蹤或金絲雀發布來測試和發布新服務。
順便說一句,為了進一步討論API網關的角色,Christian Posta最近發表了一篇有趣的博文“API網關正在經歷身份危機”。本文作者也寫過一些文章,介紹了API網關在云/容器遷移或數字轉換過程中的角色,以及如何實現將API網關與現代持續交付模型的集成。
雖然乍一看,服務網格和邊緣/API網關非常相似,但他們還是存在著一些細微的差異,而這些差異也影響了邊緣控制面板的設計。
邊緣控制面板設計
控制面板很大程度上由它所要控制的范圍以及所使用的人群決定。我的同事Rafael Schloming之前在舊金山QCon會議上談到過這個問題,他在會上討論了針對集中化或去中心化的控制實現,以及服務目前處于的開發/運營周期(原型、關鍵任務等)是如何影響控制面板實施的。
如上文所述,以邊緣代理的控制面板為例,集中化運營或SRE(網站可靠性工程師)團隊可能希望為所有的入口流量指定合理的全局默認值和安全措施。然而在第一線工作的產品開發團隊則希望能夠進行更細化的控制,并且希望能夠在本地更改全局設置。
Ambassador社區一開始就將開發人員以及應用工程師作為主要目標人群。因此他們主要關注的是基于去中心化配置的控制面板。Ambassador一開始就按照Kubernetes標準設計,因此我們最好也能夠參照Kubernetes的服務規范來配置邊緣,例如使用YAML文件,通過kubectl加載。
Ambassador的配置方式有Kubernetes Ingress對象、自定義的Kubernetes注解以及自定義資源定義(CRDs)。我們最終選擇了Kubernetes注解,因為它很簡潔,也容易上手。理論上Ingress對象是一個更好的選擇,但Ingress規范一直處于測試階段,除了管理入口流量的\u0026quot;最基本\u0026quot;功能之外,其他功能還沒怎么達成共識。
如下是一個Ambassador的注解示例,它在Kubernetes服務上實現了一個簡單的終端到服務的路由:
kind: ServiceapiVersion: v1metadata: name: my-service annotations: getambassador.io/config: | --- apiVersion: ambassador/v0 kind: Mapping name: my_service_mapping prefix: /my-service/ service: my-servicespec: selector: app: MyApp ports: - protocol: TCP port: 80 targetPort: 9376
如果你以前配置過邊緣代理、反向代理或API網關,那相信你不會對getambassador.io/config中的配置感到陌生,其主要功能就是將發送到終端前綴的流量映射到名為my-service的Kubernetes服務上。由于本文主要關注Ambassador的設計和實現,因此我們不會涵蓋可以配置的所有功能,比如路由、金絲雀發布和速率限制等。雖然Ambassador主要是面向開發人員的角色,但它也實現了很多針對運營商的擴展,并且也可以集中配置身份驗證、TLS/SNI、追蹤和服務網格集成等。
接下來讓我們再回到Ambassador,并看一下它在過去兩年中的演變。
Ambassador \u0026lt; v0.40:Envoy v1 APIs,模板以及熱重啟
Ambassador本身是部署在容器中的Kubernetes服務,并使用Kubernetes Services注解作為其核心配置模型。這種方法使應用程序開發人員可以將路由管理作為Kubernetes服務定義的一部分(也稱作\u0026quot;GitOps\u0026quot;方法)。將簡單的Ambassador注解轉換為有效的Envoy v1配置并不是一項簡單的任務,畢竟Ambassador與Envoy的配置在設計上并不相同。因此,在進行配置轉換的時候,我們本著聚合和簡化操作的目的,更改了很多Ambassador內部的邏輯。
具體來講,Kubernetes用戶可按照如下步驟完成對Ambassador的配置:
Kubernetes API異步通知Ambassador的更改。
Ambassador將配置轉換為抽象的中間代碼(IR)。
從IR中生成一個Envoy配置文件。
使用Ambassador驗證Envoy配置文件。
如果配置文件有效,Ambassador將使用Envoy的熱重新啟動機制來部署新的配置,并保持連接。
流量將會在新啟動的Envoy進程中傳輸。
這個初始實現有很多好處:首先機制簡單,其次Ambassador同Envoy之間的配置轉換是可靠的,最后Ambassador與基于文件的熱重啟的整合也是可靠的。
但是,這一版本的Ambassador仍有很多需要改善的地方。首先,盡管熱重啟對于大多數用例有效,但是它還不夠快;而且一些用戶(特別是那些部署大型應用程序的用戶)發現它限制了更改配置的頻率;最后,熱重啟有時也會中斷連接,尤其是像websocket或gRPC流這類的長期連接。
更重要的是,盡管初版Ambassador到Envoy的中間代碼(IR)允許快速原型設計,但由于功能還太初級,很難做出實質性的改變。雖然這是從一開始就存在的問題,但隨著Envoy升級到Envoy v2 API,這變成了一個關鍵問題。正如Matt Klein在他的博文“通用數據面板API“中所描述的那樣,v2 API為Ambassador提供了很多好處:諸如訪問新特性、解決上面提到的連接中斷問題,但遺憾的是現有的IR實現仍然沒有本質的提高。
Ambassador \u0026gt; v0.40: Envoy v2 API(ADS)、中間代碼、KAT測試
在與Ambassador社區協商后,Ambassador首席工程師Flynn帶領的Datawire團隊在2018年對Ambassador內部進行了重構。重構主要有兩個關鍵目標。首先,能夠集成Envoy v2的配置格式,這將支持諸如服務器名稱指示、基于標簽的速率限制和改進的身份驗證等特性。其次,能夠對Envoy配置進行更強大的語義驗證,畢竟它的復雜性越來越高(特別是在大規模應用程序部署的時候)。
Datawire團隊首先按照多遍編譯器的思路調整了Ambassador的內部結構。添加了類層次結構以便可以更好的反映Ambassador配置資源、中間代碼和Envoy配置資源之間的分離。而Datawire以外的社區也重新設計了Ambassador的核心部分。
之所以采取這些方法是處于如下幾個方面的考慮:首先,Envoy代理仍是一個快速發展的項目,我們不能每次都因為Envoy配置的微小變化就對Ambassador進行重新設計。而且,我們也希望能夠實現配置文件的語義驗證。
隨著對Envoy v2整合工作的深入,Datawire團隊很快又發現了一個測試上的問題,那就是隨著Ambassador開始支持越來越多的特征,它在處理不太常見但又正確的特征組合時出現了非常多的錯誤。這促使他們創建一個新的測試要求,而這意味著需要對Ambassador的測試套件進行重新編寫,以便能夠自動測試大部分的特性組合,而不是依靠人工來編寫每個測試用例。此外,這套測試套件需要快速,以便最大限度地提高工程效率。
因此,在對Ambassador重構的同時,Datawire團隊創建了新的Kubernetes驗收測試(KAT)框架。KAT是一個可擴展的測試框架,它的主要功能如下:
將一組服務(連同Ambassador)部署到Kubernetes集群
對分離出來的API運行一系列驗證查詢
對這些查詢結果執行一組斷言測試
KAT是為性能而設計的——它提前將測試設置打包,然后在步驟3中使用高性能HTTP客戶機異步查詢。KAT中的流量驅動程序使用了另一個開源工具Telepresence,這也讓調試診斷變的更加容易。
隨著KAT測試框架的到位,Datawire團隊又遇到了一些關于Envoy v2配置和熱重啟的問題,他們開始考慮轉換到Envoy的ADS(聚合發現服務)API。這樣完全消除了配置更改時重啟的限制,也避免了高負載或長時間連接下的中斷問題。Datawire團隊最終決定使用GO編寫的Envoy控制面板連接到ADS。但是,也增加了Ambassador代碼庫對GO的依賴。
使用新的測試框架,新的中間代碼生成有效的Envoy v2配置以及ADS,Ambassador 0.50的主要體系結構更改已經完成。現在,用戶使用含有Ambassador注解的Kubernetes清單的步驟如下:
就在發布之前,Datawire團隊又碰到了一個問題,Azure Kubernetes服務(AKS)不能正確檢測到Ambassador注解的更改。通過與AKS工程團隊的高效合作,他們很快找到了問題點——Kubernetes API服務器中的代理鏈丟掉了很多訪問請求,對此最好的緩解措施是使用支持調用API服務器的FQDN。不幸的是,這需要AKS中的mutating webhook,而官方的Kubernetes Python客戶端并沒有實現這個特性。因此,我們使用了Kubernetes Golang客戶端,這也是基于Go的第二個依賴項。
總結
正如Matt Klein在EnvoyCon開幕式上所提到的,隨著目前Envoy代理在云原生技術領域的流行,不知道Envoy的人群反而成了少數。我們知道,谷歌的Istio已經在Kubernetes用戶中提高了Envoy的知名度,現在主要的云供應商都在關注Envoy,例如,在AWS app網格和Azure Service Fabric網格。在EnvoyCon上,我們還聽說了一些大公司如eBay、Pinterest和Groupon都在使用Envoy作為他們的主要邊緣代理,還有一些其他基于Envoy的邊緣代理控制面板,如Istio Gateway、Solo.io Gloo和HeptioContour等。Envoy已經成為云原生通信的通用數據面板,當然它在控制面板領域內仍有許多工作。
在本文中,我們討論了Datawire團隊和Ambassador開源社區如何成功地將Envoy v2配置和ADS API應用到Ambassador邊緣控制面板。在構建Ambassador 0.50的過程中,我們學到了很多東西:
Kubenetes和Envoy是功能非常強大的框架,但它們也在不斷成長中——很多時候都沒有最新的文檔交付,維護人員只能通過閱讀源碼來學習。
Kubernets/Envoy生態系統中支持最好的類庫都是用Go編寫的。雖然我們喜歡Python,但是我們不得不采用Go,這樣我們就不必自己維護太多的組件。
有時候重新設計測試工具也能促進軟件開發。通常,重新設計測試工具的真正成本只是將舊的測試移植到新的工具實現。
為邊緣代理設計和實現一個有效的控制面板是很困難的,來自Kubernetes、Envoy和Ambassador開源社區的反饋非常有用。
將Ambassador遷移到Envoy v2配置和ADS API是一個漫長而艱難的過程,需要大量架構和設計上的討論,當然也少不了大量的編碼,但早期反饋的結果是積極的。Ambassador 0.50已經發布,你可以試用一下,并在Slack頻道或Twitter上分享一下你的意見。
關于作者
丹尼爾·布萊恩特,公司技術變革的領導者,自由職業顧問,Datawire是其客戶之一。他目前的工作是實現公司內部開發的敏捷性:引入更好的需求收集和規劃技術,關注敏捷開發中架構的相關性,促進持續集成和交付等。Daniel目前的技術專長集中在\u0026quot;DevOps\u0026quot;工具化、云/容器平臺和微服務實現。他同時是倫敦Java社區(LJC)的領導者,并參與了很多開源項目。他還為InfoQ、DZone和Voxxed等知名技術網站的撰稿,并定期在QCon、JavaOne和Devoxx等國際會議上發表演講。
查看英文原文:https://www.infoq.com/articles/ambassador-api-gateway-kubernetes