本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

Fission:Kubernetes 的無伺服器函式即服務

Fission 是一個基於 Kubernetes 構建的函式即服務 (FaaS) / 無伺服器函式框架。

Fission 允許您輕鬆地在 Kubernetes 上從函式建立 HTTP 服務。它在原始碼級別工作,並抽象了容器映象(在大多數情況下)。它還簡化了 Kubernetes 的學習曲線,使您無需深入瞭解 Kubernetes 即可建立有用的服務。

要使用 Fission,您只需建立函式並透過 CLI 新增它們。您可以將函式與 HTTP 路由、Kubernetes 事件或其他觸發器關聯起來。Fission 目前支援 NodeJS 和 Python。

函式在觸發器觸發時被呼叫,並且它們只在執行時消耗 CPU 和記憶體。空閒函式除了儲存之外不消耗任何資源。

為什麼要基於 Kubernetes 構建 FaaS 框架?

我們認為需要一個 FaaS 框架,它可以在各種基礎設施上執行,包括公共雲和本地基礎設施。接下來,我們必須決定是從頭開始構建它,還是在現有編排系統之上構建。很快就清楚,我們不應該從頭開始構建——我們最終只會重新發明叢集管理、排程、網路管理等等。

Kubernetes 提供了一個功能強大且靈活的編排系統,擁有全面的 API,並由一個強大且不斷壯大的社群提供支援。在此基礎上構建意味著 Fission 可以將容器編排功能留給 Kubernetes,並專注於 FaaS 功能。

我們不希望擁有獨立 FaaS 叢集的另一個原因是,FaaS 與其他基礎設施結合使用效果最佳。例如,它可能適用於小型 REST API,但它需要與其他服務協同工作才能儲存狀態。FaaS 也是一種出色的機制,可用於事件處理程式處理來自儲存、資料庫以及 Kubernetes 本身的訊息通知。Kubernetes 是所有這些服務協同工作的絕佳平臺。

部署和使用 Fission

Fission 可以透過 `kubectl create` 命令安裝:請參閱專案 README 獲取說明。

以下是如何編寫一個“hello world”HTTP 服務

$ cat \> hello.py

def main(context):

    print "Hello, world!"


$ fission function create --name hello --env python --code hello.py --route /hello


$ curl http://\<fission router\>/hello

Hello, world!

Fission 負責將函式載入到容器中,將請求路由到容器中等等。我們將在下一節中詳細介紹。

Fission 如何在 Kubernetes 上實現

FaaS 框架的核心必須 (1) 將函式轉換為服務,並且 (2) 管理這些服務的生命週期。

實現這些目標有多種方法,每種方法都有不同的權衡。框架應該在原始碼級別操作,還是在 Docker 映象級別操作(或者介於兩者之間,例如“buildpacks”)?函式首次執行時可接受的開銷是多少?這些選擇會影響平臺的靈活性、易用性、資源使用和成本,當然還有效能。

打包、原始碼和映象

我們的目標之一是讓 Fission 對新使用者來說非常易於使用。我們選擇在原始碼級別操作,這樣使用者就可以避免處理容器映象構建、將映象推送到登錄檔、管理登錄檔憑據、映象版本控制等等。
然而,容器映象是在原始碼級別操作,這樣使用者就可以避免處理容器映象構建、將映象推送到登錄檔、管理登錄檔憑據、映象版本控制等等。

然而,容器映象才是打包應用程式最靈活的方式。一個純粹的原始碼級別介面將不允許使用者打包二進位制依賴項,例如。

因此,Fission 採用混合方法——包含函式動態載入器的容器映象。這種方法允許大多數使用者純粹在原始碼級別使用 Fission,但在需要時可以自定義容器映象。

這些映象在 Fission 中被稱為“環境映象”,它們包含語言執行時(如 NodeJS 或 Python)、一組常用依賴項和函式的動態載入器。如果這些依賴項足以滿足使用者正在編寫的函式,則無需重新構建映象。否則,可以修改依賴項列表並重新構建映象。

這些環境映象僅僅是Fission中特定於語言的部分。它們向框架的其餘部分呈現統一的介面。這種設計使得Fission能夠輕鬆擴充套件到更多的語言。

冷啟動效能

無伺服器函式的目標之一是函式僅在執行時才使用 CPU/記憶體資源。這優化了函式的資源成本,但代價是當從空閒狀態啟動時會產生一些效能開銷(“冷啟動”開銷)。

冷啟動開銷在許多用例中都很重要。特別是,對於用於互動式用例的函式——例如Web或移動應用程式,使用者正在等待操作完成——幾秒鐘的冷啟動延遲是不可接受的。

為了最佳化冷啟動開銷,Fission 為每個環境都保留了一個正在執行的容器池。當一個函式的請求到來時,Fission 無需部署一個新的容器——它只需選擇一個已經執行的容器,將函式複製到容器中,動態載入它,並將請求路由到該例項。此過程的開銷對於 NodeJS 和 Python 函式大約為 100 毫秒。

Fission 在 Kubernetes 上的工作原理

fission-arch.png Fission 被設計為一組微服務。一個控制器負責跟蹤函式、HTTP
路由、事件觸發器和環境映象。一個池管理器管理空閒環境容器池、將函式載入到這些容器中以及在函式例項空閒時終止它們。一個路由器接收 HTTP 請求並將其路由到函式例項,並在必要時從池管理器請求一個例項。

控制器提供 Fission API。所有其他元件都會監視控制器以獲取更新。路由器作為 LoadBalancer 或 NodePort 型別的 Kubernetes Service 公開,具體取決於 Kubernetes 叢集的託管位置。

當路由器收到請求時,它會查詢快取以檢視該請求是否已有一個服務應路由到。如果不是,它會查詢要對映請求的函式,並向池管理器請求一個例項。池管理器有一個空閒的 Pod 池;它選擇一個,將函式載入到其中(透過向 Pod 中的一個 sidecar 容器傳送請求),並將 Pod 的地址返回給路由器。路由器將請求代理到該 Pod。該 Pod 會被快取以供後續請求使用,如果它空閒了幾分鐘,它就會被終止。

(目前,Fission 將一個函式對映到一個容器;計劃在稍後版本中實現自動擴縮到多個例項。對於不需要隔離的情況,也計劃複用函式 Pod 來託管多個函式。)

Fission 的使用場景

機器人、Webhook、REST API
Fission 是一個很好的框架,可以用來建立小型 REST API、實現 webhook 以及為 Slack 或其他服務編寫聊天機器人。

作為簡單 REST API 的一個例子,我們製作了一個小型留言簿應用程式,它使用函式來讀寫留言簿,並與 Redis 例項協同工作以跟蹤狀態。您可以在 Fission GitHub 倉庫中找到該應用程式。

該應用程式包含兩個端點——GET 端點列出 Redis 中的留言簿條目並將其渲染為 HTML。POST 端點將新條目新增到 Redis 中的留言簿列表。僅此而已——無需管理 Dockerfile,更新應用程式就像呼叫 `fission function update` 一樣簡單。

處理 Kubernetes 事件
Fission 還支援根據 Kubernetes 觀察來觸發函式。例如,您可以設定一個函式來觀察特定名稱空間中匹配特定標籤的所有 Pod。該函式在其上下文中獲取序列化物件和觀察事件型別(新增/刪除/更新)。

這些事件處理函式可用於簡單監控——例如,每當叢集中新增新服務時,您都可以傳送 Slack 訊息。還有更復雜的用例,例如透過觀察 Kubernetes 的第三方資源來編寫自定義控制器。

狀態和路線圖

Fission 目前仍處於早期 Alpha 階段(2017 年 1 月)。它尚未準備好投入生產使用。我們正在尋找早期採用者和反饋。

Fission 的未來如何?我們正在努力使 Kubernetes 上的 FaaS 更加方便、易於使用,並且更容易整合。在接下來的幾個月裡,我們正在努力增加對單元測試、與 Git 整合、函式監控和日誌聚合的支援。我們還在努力與其他事件源整合。

建立更多語言環境也在進行中。目前支援 NodeJS 和 Python。Klavs Madsen 已貢獻了 C# .NET 的初步支援。

您可以在我們的 GitHub issuesprojects 中找到我們當前的路線圖。

參與其中

Fission 是由 Platform9 Systems 公開開發的開源專案。請在 GitHub 上檢視我們,如果您想與我們聊天,請加入我們的 Slack 頻道。我們也在 Twitter 上,賬號是 @fissionio