1 Wasm為Envoy帶來新的擴展性
Envoy是一個高性能、可編程的L3/L4和L7網絡代理,許多服務網格和網關都採用Envoy作為數據面。
Envoy通過監聽器(Listener)捕獲網絡數據包,根據數據包的內容匹配某個過濾器鏈(Filter Chain)中,之後按順序執行該鏈中的過濾器(Network Filter)對捕獲的數據包進行操作,實現用户定義的各種流量治理策略。Envoy本身自帶很多種類的過濾器,這些開箱即用的過濾器 cover了大部分的應用場景,但是在某些需要自定義功能的場景下,用户必須實現自己的過濾器。
Envoy filter chains
在Wasm出現之前,添加過濾器有兩種方式:
- 修改Envoy代碼,使用C++語言編寫原生的過濾器(Native C++ filters)。在早期(2019年初),Envoy是一個靜態編譯的二進制文件,其所有擴展都在構建時編譯。這意味着提供自定義擴展的項目必須維護和分發自己的二進制文件。這種方式需要開發者熟悉C++語言和Envoy過濾器的開發模式,在開發完成後重新編譯一個新的Envoy二進制且維護它與上游社區的版本。目前Istio社區採用的就是這種方式,Istio fork了上游的Envoy,在其基礎之上添加了自己定製的一些插件。然而,這種方式對開發者要求較高,且需要花費額外的精力維護。
- 使用Lua腳本編寫過濾器。這種方式相比於上一種更加簡單,用户可以直接在xDS配置中直接編寫Lua腳本(inline)或指定本地的一個Lua腳本文件,適合過濾器邏輯非常簡單的情況。然而,這種方式並不適用於過濾器邏輯複雜的情況,而且需要用户在Istio中手動創建EnvoyFilter進行額外的配置。
可以看出,上述兩種擴展Envoy的方式都不是非常“優雅”。為了解決這個問題,Envoy社區提出了Wasm Filter特性,在Envoy中內嵌了一個Wasm運行時,通過proxy-wasm定義的網絡代理相關接口來運行Wasm二進制。這意味着Envoy可以在運行中動態地加載用户開發的Wasm模塊,並將其作為一個過濾器插入到過濾器鏈中。Wasm能夠解決上述傳統方式的各種問題,用户能夠用任何支持的語言開發自己的Wasm過濾器,對Envoy本身無侵入。Envoy發起者稱“Wasm是Envoy可擴展性的未來”。
Envoy與Wasm的交互
2 Istio WasmPlugin API
Envoy對Wasm的支持為Istio帶來了全新的擴展機制。在早期,用户可以使用EnvoyFilter手動在Envoy配置中添加Wasm filter,這種方式非常地繁瑣,用户體驗並不友好,且EnvoyFilter是一個“break glass”API,社區並不保證其不同版本的向後兼容性。
為了更好地支持Wasm,Istio在1.12版本中添加了一個新的CRD,即WasmPlugin。用户可以通過WasmPlugin方便靈活地將Wasm插件下發到指定的工作負載,使得開發人員可以更簡單健壯地擴展網格功能。
WasmPlugin yaml示例
上圖展示了一個最基本的WasmPlugin配置,在配置中用户需要指定Wasm模塊的url,該url可以是像容器鏡像一樣的OCI格式的Wasm,也可以是代理本地的一個文件(通常要求用户手動掛載到容器中),或者是http協議的url,用於直接獲取遠程Wasm模塊文件。一般推薦的方式第是一種,將編寫好的代碼編譯成Wasm二進制後,打包成一個OCI鏡像,方便分發和復現。
用户可以通過selector指定要下發Wasm的proxy,如果selector為空,則代表下發到該namespace下的所有proxy。
除此之外,如果用户需要指定Wasm插件在過濾器鏈中執行的位置,可以通過phase和priority兩個參數來控制。phase用來指定在http filter鏈中的何處插入此Wasm 插件,可以設置為authentication,authorization或istio stats filter之前,未設置時會在istio stats filter之後插入;priority用來控制多個WasmPlugin在同一個phase中的執行順序,priority值大的優先。
03Istio下發Wasm配置流程解析
Istiod推送過程
每當用户更新WasmPlugin時,istiod就會觸發一次config update。首先,istiod會更新本次xDS push的context,將當前的WasmPlugin信息按照namespace分類,保存到push context中。
之後,在LDS(Listener Discovery Service)推送的過程中,istiod為proxy構建Listener的http filter時,會從push context中找出與該proxy匹配的WasmPlugin並按照priority排序,最後根據phase將Wasm filter插入到http filter chain中的某個位置。
Istio插入Wasm filter代碼
注意此處插入的只是Wasm filter的名稱,具體的Wasm filter配置則是通過後續的ECDS(Extension Config Discovery Service)下發的。在ECDS中,istiod會構建出實際的Wasm filter配置並推送給proxy。
Wasm filter envoy配置示例
04 Proxy接收過程Proxy接收過程
Envoy的Wasm filter配置本身是不支持使用OCI鏡像格式作為data source的。那麼Istio是如何支持使用OCI鏡像分發Wasm二進制的呢?
答案是通過istio-agent的代理。Istio的proxy中包含兩個進程,一個是Envoy本身,另一個是istio-agent。istio-agent會代理Envoy與istiod之間的xDS通信。對於ECDS,istio-agent在收到推送時,會讀取其內容,假如其中的Wasm filter使用OCI鏡像或者http/https作為data source(即需要執行的Wasm二進制),那麼istio-agent會從遠程倉庫中拉取該Wasm二進制並緩存至本地。之後會修改ECDS的內容,將Wasm filter的data source改為剛才保存的本地文件,再將修改後的ECDS內容發送給Envoy。
對Wasm為Envoy帶來新的擴展性的價值簡要總結:綜上,Envoy和Istio對Wasm的支持大大加強了服務網格的擴展性。用户通過Wasm能夠以可擴展、靈活、安全的方式對代理進行自定義配置,應對各種場景的業務需求,例如認證、授權、Tracing、請求內容轉換/檢查等等。同時,Istio提供的API使Wasm成為了服務網格中的“一等公民”,用户可以方便地將Wasm下發到指定的工作負載,該過程是完全動態的,應用無需重啓。這種高效率的擴展方式使得服務網格具備了可編程性。
05 未來展望
目前,Wasm仍在快速發展,相關的特性在Istio和Envoy中還處在alpha階段。為了加速Wasm生態,讓所有Wasm程序有一個“common language”,社區正在設計一個標準的Wasm interface —— WASI(WebAssembly System Interface),用於訪問和操作系統資源。未來proxy-wasm可能會與WASI融合,為Wasm程序提供一個標準的交互接口。同時,Wasm將支持更多高級語言作為前端,用於構建輕量、高性能的應用程序。隨着Wasm生態的逐步成熟,期待它能在雲計算領域中帶來更多令人興奮的可能性。