終于有人把Knative講明白了
其基本信息如表2-2所示。
▼表2-2 Knative基本信息
Knative一個很重要的目標就是制定云原生、跨平臺的Serverless編排標準。Knative是通過整合容器構(gòu)建(或者函數(shù))、工作負載管理(和動態(tài)擴縮)以及事件模型來實現(xiàn)Serverless標準的。Knative社區(qū)的主要貢獻者有Google、Pivotal、IBM、Red Hat。CloudFoundry、OpenShift這些PaaS提供商都在積極地參與Knative的建設(shè)。
1.工作原理
如圖2-14所示,Knative是建立在Kubernetes和Istio平臺之上的,使用了Kubernetes提供的容器管理組件(deployment、replicaset和pod等),以及Istio提供的網(wǎng)絡(luò)管理組件(ingress、LB、dynamic route等)。
Knative中有兩個重要的組件,分別是為其提供流量的Serving(服務(wù))組件以及確保應(yīng)用程序能夠輕松地生產(chǎn)和消費事件的Event(事件)組件。
其中,Serving組件基于負載自動伸縮,包括在沒有負載時縮減到零,允許使用者為多個修訂版本應(yīng)用創(chuàng)建流量策略,從而通過URL輕松路由到目標應(yīng)用程序;而Event組件的作用是使生產(chǎn)和消費事件變得容易,允許操作人員使用自己選擇的消息傳遞層。
除了Serving和Event組件之外,Build也是Kantive的組件之一。其提供“運行至完成”的顯示功能,這對創(chuàng)建CI/CD工作流程很有用,通過靈活的插件化的構(gòu)建系統(tǒng)將用戶源代碼構(gòu)建成容器。
目前,其已經(jīng)支持多個構(gòu)建系統(tǒng),比如Google的Kaniko,它無須運行Docker Daemon就可以在Kubernetes集群上構(gòu)建容器鏡像。Serving使用它將源存儲庫轉(zhuǎn)換為包含應(yīng)用程序的容器鏡像。
在諸多Serverless開源項目中,Knative的優(yōu)勢也是較為明顯的。一方面,Knative以Kubernetes為底層框架,與Kubernetes生態(tài)結(jié)合得更緊密。無論是云上Kubernetes服務(wù)還是自建Kubernetes集群,都能通過安裝Knative插件快速地搭建Serverless平臺。
另一方面,Knative聯(lián)合CNCF,把所有事件標準化為CloudEvent,提供事件的跨平臺運行,同時讓函數(shù)和具體的調(diào)用方法解耦。在彈性層面,Knative可以監(jiān)控應(yīng)用的請求,并自動擴縮容,借助于Istio(Ambassador、Gloo等)支持藍綠發(fā)布、回滾的功能,方便應(yīng)用發(fā)布。
同時,Knative支持日志的收集、查找和分析,并支持VAmetrics數(shù)據(jù)展示、調(diào)用關(guān)系跟蹤等。
Knative工作原理如圖2-14所示。
▲圖2-14 Knative工作原理
2.功能與策略
(1)Serving(服務(wù))
Serving模塊定義了一組特定的對象,包括Revision(修訂版本)、Configuration(配置)、Route(路由)和Service(服務(wù))。Knative通過Kubernetes CRD(自定義資源)的方式實現(xiàn)這些Kubernetes對象。所有Serving組件對象間的關(guān)系可以參考圖2-15。
▲圖2-15 Serving組件對象間的關(guān)系
Knative Serving始于Configuration。使用者在Configuration中為部署容器定義所需的狀態(tài)。最小化Configuration至少包括一個配置名稱和一個要部署容器鏡像的引用。
在Knative中,定義的引用為Revision。Revision代表一個不變的、某一時刻的代碼和Configuration的快照。每個Revision引用一個特定的容器鏡像和運行它所需要的特定對象(例如環(huán)境變量和卷)。然而,使用者不必顯式創(chuàng)建Revision。Revision是不變的,它們從不會被改變和刪除。
相反,當使用者修改Configuration的時候,Knative會創(chuàng)建一個Revision。這使得一個Configuration既可以反映工作負載的當前狀態(tài),也可以用于維護一個歷史的Revision列表。
Knative中的Route提供了一種將流量路由到正在運行的代碼的機制。它將一個HTTP可尋址端點映射到一個或者多個Revision。Configuration本身并不定義Route。
(2)彈性伸縮
Serverless架構(gòu)的一個關(guān)鍵原則是可以按需擴容,以滿足需要和節(jié)省資源。Serverless負載應(yīng)當可以一直縮容至零。這意味著如果沒有請求進入,則不會運行容器實例。如圖2-16所示,Knative使用兩個關(guān)鍵組件實現(xiàn)該功能。它將Autoscaler和Activator實現(xiàn)為集群中的Pod。
▲圖2-16 Knative彈性伸縮原理簡圖
用戶可以看到它們伴隨其他Serving組件一起運行在knative-serving命名空間中。Autoscaler收集達到Revision并發(fā)請求數(shù)量的有關(guān)信息。為了做到這一點,它在Revision Pod內(nèi)運行一個名為queue-proxy的容器。該Pod中也運行用戶提供的鏡像。
queue-proxy檢測該Revision上觀察到的并發(fā)量,然后每隔一秒將此數(shù)據(jù)發(fā)送到Autoscaler。Autoscaler每隔兩秒對這些指標進行評估,并基于評估的結(jié)果增加或者減少Revision部署的規(guī)模。默認情況下,Autoscaler嘗試維持每Pod每秒平均接收100個并發(fā)請求。這些并發(fā)目標和平均并發(fā)窗口均可以變化。
Autoscaler也可以利用Kubernetes HPA(Horizontal Pod Autoscaler)來替代該默認配置。這將基于CPU使用率實現(xiàn)自動伸縮,但不支持縮容至零。這些設(shè)定都能夠通過Revision元數(shù)據(jù)注解(Annotation)定制。
Autoscaler采用的伸縮算法針對兩個獨立的時間間隔計算所有數(shù)據(jù)點的平均值。它維護兩個時間窗,分別是60秒和6秒。Autoscaler以兩種模式運作:Stable Mode(穩(wěn)定模式)和Panic Mode(恐慌模式)。在穩(wěn)定模式下,它使用60秒時間窗的平均值決定如何伸縮部署以滿足期望的并發(fā)量。
如果6秒時間窗的平均并發(fā)量兩次達到期望目標,Autoscaler轉(zhuǎn)換為恐慌模式并使用6秒時間窗。這讓它更加快捷地響應(yīng)瞬間流量的增長。它也僅僅在恐慌模式下擴容以防止Pod數(shù)量快速波動。如果超過60秒沒有發(fā)生擴容,Autoscaler會轉(zhuǎn)換回穩(wěn)定模式。
(3)Build(構(gòu)建)
Knative的Serving(服務(wù))組件是解決如何從容器到URL的,而Build組件是解決如何從源代碼到容器的。Build資源允許用戶定義如何編譯代碼和構(gòu)建容器。這確保了在將代碼發(fā)送到容器鏡像庫之前以一種一致的方式編譯和打包代碼。下面介紹一些新的組件。
- Build:驅(qū)動構(gòu)建過程的自定義Kubernetes資源。在定義構(gòu)建時,用戶需要定義如何
獲取源代碼以及如何創(chuàng)建容器鏡像來運行代碼。
- Build Template:封裝可重復(fù)構(gòu)建步驟以及允許對構(gòu)建進行參數(shù)化的模板。
- Service Account:允許對私有資源(如Git倉庫或容器鏡像庫)進行身份驗證。
(4)Event(事件)
到目前為止,向應(yīng)用程序發(fā)送基本的HTTP請求是一種有效使用Knative函數(shù)的方式。無服務(wù)器的松耦合特性同時也適用于事件驅(qū)動架構(gòu)。也就是說,可能在文件上傳到FTP服務(wù)器時需要調(diào)用一個函數(shù);或者任何時間發(fā)生一筆物品銷售時需要調(diào)用一個函數(shù)來處理支付和庫存更新的操作。
與其讓應(yīng)用程序或函數(shù)考慮監(jiān)聽事件的邏輯,不如當那些被關(guān)注的事件發(fā)生時,讓Knative去處理并通知我們。
自己實現(xiàn)這些功能則需要做很多工作并要編寫實現(xiàn)特定功能的代碼。幸運的是,Knative提供了一個抽象層使消費事件處理變得更容易。
Knative直接提供了一個“事件”,而不需要編寫特定的代碼來選擇消息代理。當事件發(fā)生時,應(yīng)用程序無須關(guān)心它來自哪里或發(fā)到哪里,只需要知道事件發(fā)生了即可。如圖2-17所示,為實現(xiàn)這一目標,Knative引入了三個新的概念:Source(源)、Channel(通道)和Subscription(訂閱)。
- Source(源):事件的來源,用于定義事件在何處生成以及如何將事件傳遞給關(guān)注對象的方式。
- Channel(通道):通道處理緩沖和持久性,即使該服務(wù)已被關(guān)閉,也可確保將事件傳遞到預(yù)期的服務(wù)。另外,通道是代碼和底層消息傳遞解決方案之間的一個抽象層。這意味著可以像Kafka和RabbitMQ一樣在某些服務(wù)之間進行消息交換,但在這兩種情況下都不需要編寫特定的實現(xiàn)代碼。
- Subscription(訂閱):將事件源發(fā)送到通道,并準備好處理它們的服務(wù),但目前沒有辦法獲取從通道發(fā)送到服務(wù)的事件。為此,Knative設(shè)計了訂閱功能。訂閱是通道和服務(wù)之間的紐帶,指示Knative如何在整個系統(tǒng)中管理事件。
▲圖2-17 Knative事件處理模型簡圖
Knative中的服務(wù)不關(guān)心事件和請求是如何獲取的。它可以獲取來自入口網(wǎng)關(guān)的HTTP請求,也可以獲取從通道發(fā)送來的事件。無論通過何種方式獲取,服務(wù)僅接收HTTP請求。這是Knative中一個重要的解耦方式。它確保將代碼編寫到架構(gòu)中,而不是在底層創(chuàng)建訂閱、通道向服務(wù)發(fā)送事件。
關(guān)于作者:劉宇(花名:江昱),國防科技大學(xué)電子信息專業(yè)博士,阿里云Serverless產(chǎn)品體驗側(cè)負責(zé)人,從事Serverless相關(guān)的工作多年,負責(zé)阿里云函數(shù)計算(FC)、Serverless工作流(FNF)等產(chǎn)品的體驗工作,有豐富的實踐經(jīng)驗。阿里云戰(zhàn)略級開源項目Serverless Devs發(fā)起人和負責(zé)人,Serverless Framework、Kubevela等開源項目貢獻者,社區(qū)項目Anycodes在線編程負責(zé)人。
本文摘編自《Serverless工程實踐:從入門到進階》,經(jīng)出版方授權(quán)發(fā)布。