OpenFunction:新一代開源函數計算平臺

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"作者 | 方闐(OpenFunction Maintainer)、霍秉傑 (OpenFunction 發起人)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"【編者按】"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你有開源項目想要尋求報道,歡迎聯繫微信caifangfang842852(請註明姓名和來由)。"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"概述"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"無服務器計算,即通常所說的 Serverless,已經成爲當前雲計算領域的熱門話題與趨勢技術。無服務器計算是一種契合於當下雲原生生態的開發、運行模式。無服務器並非不依賴服務器,而是對開發者而言服務器被抽象爲更精確的算力單元。加州大學伯克利分校在論文 "},{"type":"link","attrs":{"href":" A Berkeley View on Serverless Computinghttps:\/\/www2.eecs.berkeley.edu › EECS-2019-3","title":null,"type":null},"content":[{"type":"text","text":"A Berkeley View on Serverless Computing"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 中提出的關於 Serverless 的觀點——Serverless computing = FaaS + BaaS 被廣泛接受,而 FaaS (函數即服務) 是 Serverless 的核心。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"自 AWS Lambda 面世後,各大雲計算巨頭廠商紛紛投入 Serverless 戰場,爭相推出各自的 Serverless 或 FaaS 平臺。另一方面,開發者不希望被特定廠商綁定的意願也讓開源的 Serverless 項目有了一席之地。如今 "},{"type":"link","attrs":{"href":"https:\/\/www.openfaas.com\/","title":null,"type":null},"content":[{"type":"text","text":"OpenFaaS(faas 倉庫 20.3k)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/kubeless.io\/","title":null,"type":null},"content":[{"type":"text","text":"Kubeless(6.7k)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/fission.io\/","title":null,"type":null},"content":[{"type":"text","text":"Fission(6.4k)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/openwhisk.apache.org\/","title":null,"type":null},"content":[{"type":"text","text":"OpenWhisk(5.4k)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/knative.dev\/","title":null,"type":null},"content":[{"type":"text","text":"Knative(serving 倉庫 3.9k)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"社區已經擁有大量的擁簇與開發者。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"那麼爲什麼 "},{"type":"link","attrs":{"href":"https:\/\/kubesphere.io\/","title":null,"type":null},"content":[{"type":"text","text":"KubeSphere"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 社區要做一個自己的 FaaS 項目而不是直接集成現有的主流 Serverless 或 FaaS 框架?或者說現在的 Serverless 市場爲什麼還需要 "},{"type":"link","attrs":{"href":"https:\/\/openfunction.dev\/","title":null,"type":null},"content":[{"type":"text","text":"OpenFunction"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" ?"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Serverless 新願景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"根據 CNCF 的雲原生報告可以看出,Kubernetes 在容器編排技術領域擁有絕對的優勢,甚至可以將 Kubernetes 作爲雲原生的代名詞。雲原生是目前備受矚目的技術潮流,該領域的創新非常活躍,陸續湧現出了衆多優秀的開源項目(比如 Serverless 領域的 KEDA、Knative 等),並且還將繼續引領技術趨勢。在 Kubernetes 宣佈 1.20 版本將棄用 Docker、不再將其作爲默認的容器運行時之後,儘管 Docker 仍然佔據着容器運行時領域最大的份額,但對於雲原生開發者來說,不得不開始着手順應這方面的變化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"與此同時,人們生活方式的變化不斷催生新的業務模式,5G、大數據、邊緣計算、AI 推理、圖數據庫等服務應運而生。這些應用場景不但擴大了 Serverless 的潛在市場,結合雲原生的技術潮流也孵化出很多新的技術,如 "},{"type":"link","attrs":{"href":"https:\/\/dapr.io\/","title":null,"type":null},"content":[{"type":"text","text":"Dapr"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/webassembly.org\/","title":null,"type":null},"content":[{"type":"text","text":"WebAssembly"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 等。如何突破現有項目的侷限引入更新更強力的技術,如何抹平運行時之間的差異降低應用的開發成本,逐漸成爲了開發者的新煩惱。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OpenFunction 項目背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ad\/ad7178adeaa44889526d9689fb507deb.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":"https:\/\/github.com\/OpenFunction\/OpenFunction","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/github.com\/OpenFunction\/OpenFunction","title":"xxx","type":null},"content":[{"type":"text","text":"OpenFunction"}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 是 KubeSphere 社區發起的開源 FaaS 項目,目前的核心開發人員均來自 KubeSphere 團隊。KubeSphere 社區一直陸續收到社區用戶對 Serverless 或 FaaS 功能的需求,也注意到了社區開發者參與 Serverless 開發的興趣:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"KubeSphere 是否有計劃集成 Knative ?我願意參與開發!"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"KubeSphere 有 FaaS 方面的計劃嗎?是否可以集成 OpenFaaS ?"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"可否提供日誌告警的功能?這個需求本質上是可自動伸縮的異步數據處理。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"和雲原生一樣,Serverless 是個不容錯失的賽道。僅僅集成現有的 Serverless 或 FaaS 項目還不足以體現 Serverless 這個領域的重要性,於是 KubeSphere 社區從 2020 年下半年開始對 Serverless 領域進行深度調研。經過一段時間的調研後,我們發現:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"現有開源 FaaS 項目絕大多數啓動較早,大部分都在 Knative 出現前就已經存在了;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"Knative 是一個非常傑出的 Serverless 平臺,但是 Knative Serving 僅僅能運行應用,不能運行函數,還不能稱之爲 FaaS 平臺;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"Knative Eventing 也是非常優秀的事件管理框架,但是設計有些過於複雜,用戶用起來有一定門檻;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"OpenFaaS 是比較流行的 FaaS 項目,但是技術棧有點老舊,依賴於 Prometheus 和 Alertmanager 進行 Autoscaling,在雲原生領域並非最專業和敏捷的做法;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"近年來雲原生 Serverless 相關領域陸續湧現出了很多優秀的開源項目如 "},{"type":"link","attrs":{"href":"https:\/\/keda.sh\/","title":null,"type":null},"content":[{"type":"text","text":"KEDA"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、 "},{"type":"link","attrs":{"href":"https:\/\/dapr.io\/","title":null,"type":null},"content":[{"type":"text","text":"Dapr"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、 "},{"type":"link","attrs":{"href":"https:\/\/buildpacks.io\/","title":null,"type":null},"content":[{"type":"text","text":"Cloud Native Buildpacks(CNB)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、 "},{"type":"link","attrs":{"href":"https:\/\/tekton.dev\/","title":null,"type":null},"content":[{"type":"text","text":"Tekton"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、 "},{"type":"link","attrs":{"href":"https:\/\/shipwright.io\/","title":null,"type":null},"content":[{"type":"text","text":"Shipwright"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 等,爲創建新一代開源 FaaS 平臺打下了基礎。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"綜上所述,我們調研的結論就是:"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"現有開源 Serverless 或 FaaS 平臺並不能滿足構建現代雲原生 FaaS 平臺的要求,而云原生 Serverless 領域的最新進展卻爲構建新一代 FaaS 平臺提供了可能。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"於是 KubeSphere 社區決定發起 OpenFunction 項目,其目標是構建新一代開源函數計算平臺。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"開源項目與社區發展"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"截至 2021 年 8 月, OpenFunction 陸續發佈了 4 個版本,在最新的 v0.3.1 版裏 builder 和 serving 部分已經趨於穩定,並且發佈了 OpenFunction 自己的事件驅動框架 OpenFunction Events。KubeSphere 社區將持續在 OpenFunction 進行投入,最新路線圖詳見 "},{"type":"link","attrs":{"href":"https:\/\/github.com\/OpenFunction\/OpenFunction\/blob\/main\/docs\/roadmap.md","title":null,"type":null},"content":[{"type":"text","text":"OpenFunction Roadmap"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前青雲全象低代碼平臺已經採用 OpenFunction 實現靈活的低代碼平臺插件機制"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":";也有來自 Nebula 的社區用戶用 OpenFunction 實現了語音助手;有社區開發者爲 OpenFunction 社區貢獻了 NodeJS 版的 Function Framework 和 Builder。隨着項目逐漸成熟,會有越來越多的社區用戶使用 OpenFunction,我們也期待有更多的社區開發者參與進來。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OpenFunction FaaS 框架設計詳解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"OpenFunction 是一個開源的函數即服務(FaaS)框架,和大多數同類產品一樣,旨在讓用戶專注於他們的業務邏輯,而不必擔心底層運行環境和基礎設施。如下圖所示函數生命週期中幾個重要的部分分別是: 函數框架(Functions framework)、函數構建 (Build)、函數服務 (Serving)和事件驅動框架 (Events Framework),下面我們將分別詳細闡述這幾個重要部分的設計及架構。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/27\/2740c2a1626e4a595aca01c6da293080.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#7b7f83","name":"user"}},{"type":"strong"}],"text":"OpenFunction 函數生命週期示意圖"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"函數框架(Functions framework)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在 FaaS 框架中,怎樣將一段函數代碼轉換爲可運行的應用是一個重要的環節。我們知道函數計算之所以降低了開發成本,正是因爲函數框架(Functions framework)代替開發者完成了很多與業務無關的工作。不僅如此,函數框架還爲開發者提供了應用運行環境中的上下文和語義明確的函數開發擴展庫(可以理解爲 SDK)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"這部分的設計並不複雜,實現的難點在於如何做到上述的"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"語義明確"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"和"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"功能強大"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們調研了幾種主流的 FaaS 框架(平臺),發現大部分的項目選擇了封裝函數入參的做法,其意圖在於抽象輸入數據的處理方式,即無論請求是什麼格式,都可以使用框架提供的函數擴展庫來獲取數據。在這些成熟的案例中,我們發現封裝入參的方式可以使函數在同一個框架內具有很高的靈活性和可擴展性。當函數的數據輸入源變更後,函數本身不需要再做對應的入參適配,從而降低了使用者的開發成本。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"從這個角度看,封裝入參方式比不封裝(或自定義)入參方式具備更大的潛力。接受了這個設定之後,我們再來看看函數框架的本質。函數框架本質上可以歸納爲以下三個作用:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"將用戶提供的函數轉換成可以運行的應用;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"將用戶函數封裝爲一個標準的訪問地址,提供給輸入端;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"將輸出端封裝爲一個標準的訪問地址,提供給用戶函數。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"如果你瞭解過 Dapr,你就會發現後面兩點和 Dapr 的工作原理幾乎一致。Dapr 是一種分佈式應用運行時,它以一種優雅的方式簡化了開發者與中間件的交互。在 Kubernetes 中,Dapr 可以看作以 Sidecar 的方式實現了函數轉換的功能。那麼是否能用 Dapr 作爲 FaaS(Serverless)平臺中的 Functions framework?答案是肯定的。OpenFunction 正是基於 Dapr 提供了一套靈活的 functions framework 機制(其中包含了借鑑 Google functions-framework 處理 HTTP 函數的部分)實現了與各種複雜中間件的對接,並搭載兩種運行時——以 Knative serving 爲基礎的同步函數運行時,和以 KEDA 結合 Dapr 爲基礎的異步函數運行時 OpenFunctionAsync,以期實現對實際生產中大部分應用場景的覆蓋。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"爲了能讓這個函數框架真正運作起來,往往還需要藉助一些函數範圍外的配置,用於定義函數和觸發器、數據源、數據目標之間的關聯關係。我們稱之爲函數上下文(OpenFunction Context),理論上它通常具備以下內容:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"numberedlist","attrs":{"start":null,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"使用者通用元數據,如用戶 ID、RequestID 等其他上下文信息;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"事件源的定義,如名稱、類型、服務地址、數據類型等;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"觸發器的定義,如名稱、類型、觸發規則、觸發週期、執行方式等;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"函數的定義,如名稱、監聽地址等;"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"提供自定義的 key-value 參數,如環境變量,以及用於適配不同的 Runtime 等。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/bc\/bc7da8cec292cffdee570af760e3a181.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#7b7f83","name":"user"}},{"type":"strong"}],"text":"OpenFunction 組件示意圖"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"函數構建(Build)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們通常會用 Build 來指代容器鏡像的打包,但實際上將源代碼打包成鏡像只是構建工作中的一個步驟,開發者還有諸如拉取代碼、代碼預處理、鏡像上傳等工作需要完成。由此我們將 Build 拆分爲兩個主要的功能點,即製作容器鏡像與創建構建流水線。在調研了 "},{"type":"link","attrs":{"href":"https:\/\/buildpacks.io\/","title":null,"type":null},"content":[{"type":"text","text":"Cloud Native Buildpacks(CNB)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/tekton.dev\/","title":null,"type":null},"content":[{"type":"text","text":"Tekton"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/shipwright.io\/","title":null,"type":null},"content":[{"type":"text","text":"Shipwright"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 等開源項目後,我們最終設計了 OpenFunction Builder CRD,"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"爲用戶提供了一種可以自由選擇 Build 方案的 Build 框架。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"Docker 被 Kubernetes 放棄作爲默認的容器運行時後,我們在 Kubernetes 中製作容器鏡像還有多種選擇比如 Kaniko、Buildah、BuildKit 以及 Cloud Native Buildpacks(CNB)。其中前三者均依賴 Dockerfile 去製作容器鏡像,而 Cloud Native Buildpacks(CNB)是雲原生領域最新湧現出來的新技術,它不依賴於 Dockerfile,而是能自動檢測要 build 的代碼,並生成符合 OCI 標準的容器鏡像,已經被 Google Cloud、IBM Cloud、Heroku、Pivotal 等公司採用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"OpenFunction 選擇 "},{"type":"link","attrs":{"href":"https:\/\/buildpacks.io\/","title":null,"type":null},"content":[{"type":"text","text":"Cloud Native Buildpacks(CNB)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 作爲容器鏡像製作的默認選擇,陸續也會支持 Kaniko、Buildah、BuildKit 等方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/buildpacks.io\/","title":null,"type":null},"content":[{"type":"text","text":"Cloud Native Buildpacks(CNB)"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 的核心是 "},{"type":"link","attrs":{"href":"https:\/\/buildpacks.io\/docs\/concepts\/components\/lifecycle\/","title":null,"type":null},"content":[{"type":"text","text":"CNB Lifecycle"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",它負責將由應用源代碼到鏡像的構建步驟抽象出來,形成一套標準規範從而完成對整個過程的編排,並最終產出應用鏡像。這樣一來,開發者就可以將不同邏輯的最小構建單元 buildpack(可以理解爲 Dockerfile 中的鏡像分層) 按自身的需求組合到一起,生成一個構建器(builder),再交由 CNB 處理鏡像的構建過程。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"因爲這是一套開源的標準,所以在 OpenFunction Builder 中開發者不但可以選擇 OpenFunction 自身的構建器(builder)來構建鏡像,還可以選擇任何一種符合 CNB Lifecycle 的構建器,如 "},{"type":"link","attrs":{"href":"https:\/\/github.com\/GoogleCloudPlatform\/buildpacks","title":null,"type":null},"content":[{"type":"text","text":"Google buildpacks"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"、"},{"type":"link","attrs":{"href":"https:\/\/github.com\/paketo-buildpacks","title":null,"type":null},"content":[{"type":"text","text":"Paketo buildpacks"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 等,這意味着使用者可以構建任何語言、類型的應用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"Build 的另一個需求——構建流水線,就需要藉助 Tekton 這樣優秀的流水線工具作爲支持。在最開始的版本中,OpenFunction 毫不猶豫地選擇 Tekton 來拆分構建環節的工作,爲之前所談到的構建任務在 Tekton 中創建對應的 Task 及 Pipeline 等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在對 Shipwright 的調研中我們發現 Shipwright 同樣由 Tekton 驅動,並且 Shipwright 將 Tekton 的設計理念帶入了鏡像構建過程,形成了非常雲原生的鏡像構建框架,同時也支持使用 Kaniko、Buildah、BuildKit 以及 Cloud Native Buildpacks(CNB)構建鏡像,並可以通過指定 BuildStrategy 和 ClusterBuildStrategy 在上述四種鏡像構建方法之間進行切換。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"於是我們在 v0.3.0 版本中將原有的 Tekton + Cloud Native Buildpacks 的構建方案切換成了 Shipwright。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"OpenFunction Builder 從設計上完美解決了如何在沒有 Dockerfile 的情況下製作容器鏡像的問題,並且具備了高度自由、雲原生的構建器(構建方案)選擇機制"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。無論是使用現成的 Dockerfile 還是僅用一段源代碼,OpenFunction Builder 都可以將其構建爲 Open Container Initiative(OCI)標準鏡像並上傳到指定的倉庫中。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"函數服務(Serving)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"函數服務 (Serving)指的是如何運行函數\/應用,以及賦予函數\/應用基於事件驅動或流量驅動的自動伸縮的能力(Autoscaling)。我們根據這兩個方面設計了負責運行函數\/應用的 OpenFunction Serving CRD,並將函數分爲同步函數和異步函數。同步函數是指客戶端發出請求後,必須等到函數執行完成並獲取函數運行結果後才返回;異步函數是指客戶端觸發函數後,無需等待函數運行結束即可返回。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在同步函數方面,Knative Serving 具備了非常出色的自動伸縮機制,OpenFunction 支持 Knative Serving 作爲同步函數運行時,未來還將基於 KEDA http-add-on 開發 OpenFunctionSync 同步函數運行時。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"在異步函數方面,我們結合 "},{"type":"link","attrs":{"href":"https:\/\/keda.sh\/","title":null,"type":null},"content":[{"type":"text","text":"KEDA"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 和 "},{"type":"link","attrs":{"href":"https:\/\/dapr.io\/","title":null,"type":null},"content":[{"type":"text","text":"Dapr"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 開發了 OpenFunctionAsync 異步函數運行時。 Dapr 用於解耦函數對各種中間件的訪問;KEDA 提供了 ScaledObject 和 ScaledJob 兩種資源,用於根據實際事件源的監控指標自動進行工作負載副本數量的伸縮,它很好地彌補了 Knative Serving 在非 HTTP 驅動源場景中的不足。同時 KEDA 也在持續開發可以處理 HTTP 請求的 "},{"type":"link","attrs":{"href":"https:\/\/github.com\/kedacore\/http-add-on","title":null,"type":null},"content":[{"type":"text","text":"http-add-on"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 項目,這使得 OpenFunction 在後續的演進中具備了更多的選擇,OpenFunction 未來將集成 KEDA http-Add-on 實現不依賴 Knative Serving 的 OpenFunctionSync 運行時。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們將上面的工作集合起來,即使用 OpenFunction Serving CRD 來管理控制函數運行的整個生命週期。Serving CRD 包含了使用者對函數類型、輸入、輸出端的定義,以及函數實例自動伸縮的定義。OpenFunction Controller 會按照這些定義,生成相應的 Knative Service、Dapr 和 KEDA 組件,其中 Knative Service 負責同步函數的運行與自動伸縮;KEDA 會負責異步函數的自動伸縮,而 Dapr 會負責異步函數對接外部輸入\/輸出。展開來講, Dapr 會將外部的輸入通過 OpenFunction Context 傳遞給 Functions framework,進而傳遞給函數;函數執行完成會通過調用 Functions framework 中相應的函數將輸出通過 Dapr 輸出到外部。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"事件驅動框架 (Events Framework)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/57\/571c829c07ae2adc1cca3f322a7c4aa9.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#7b7f83","name":"user"}},{"type":"strong"}],"text":"OpenFunction 事件框架示意圖"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"除了核心的 FaaS 框架之外,OpenFunction 也設計了事件驅動框架以實現對異步函數的驅動。目前事件框架參考了 "},{"type":"link","attrs":{"href":"https:\/\/argoproj.github.io\/argo-events\/","title":null,"type":null},"content":[{"type":"text","text":"Argo Events"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 與 "},{"type":"link","attrs":{"href":"https:\/\/knative.dev\/docs\/eventing\/","title":null,"type":null},"content":[{"type":"text","text":"Knative Eventing"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 的部分設計,同時避免了引入類似 Knative Eventing 中過於複雜的設計;通過引入 Dapr 解耦了 EventBus 與底層具體 Message Broker 的綁定,進而利用 Dapr 的 binding 和 pubsub 分別對接事件源與 EventBus,以更優雅和可插拔的方式實現了類似 Argo Events 的架構,具備了對事件源的條件判斷、對事件的流轉控制等能力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"本質上來看,事件框架也是一個由事件驅動的工作負載,那麼它本身可以是 Serverless 形式的工作負載嗎?可以用 OpenFunction 的異步函數來驅動嗎?其實 OpenFunction 社區已將該設計列入路線圖中,目前也已實現部分組件的自驅動能力。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"OpenFunction 的挑戰"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"我們從一些關於 Serverless 的報告中可以看出,Serverless 服務有着可觀的市場潛力,未來五年內也許就會達到千億級的市場規模。然而對於 Serverless 技術本身來說,仍有很多待解決的問題,如冷啓動、安全性、可觀測性等等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"OpenFunction 在發展的過程中非常看中趨勢中的技術,相信它們可以帶來活力與變革能力(也許 "},{"type":"link","attrs":{"href":"https:\/\/github.com\/OpenFunction\/OpenFunction","title":"xxx","type":null},"content":[{"type":"text","text":"https:\/\/github.com\/OpenFunction\/OpenFunction"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" 會成爲 OpenFunction 的下一個服務運行時)。"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}},{"type":"strong"}],"text":"將成熟的與新生的技術掰開揉碎和在一起,再穿插進獨立的設計與思考,或許就是 OpenFunction 解決上述問題的後發者優勢"},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":",當然也是 OpenFunction 當下面臨的挑戰。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"加入 OpenFunction 社區"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"期待感興趣的開發者加入 "},{"type":"link","attrs":{"href":"https:\/\/github.com\/OpenFunction","title":null,"type":null},"content":[{"type":"text","text":"OpenFunction 社區"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]},{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"。可以提出任何你對 OpenFunction 的疑問、設計提案與合作提議。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}],"text":"你可以在這裏找到 OpenFunction 的一些典型使用案例:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s\/EZWYqtXJ7Cj-Yd7Fro6uyA","title":null,"type":null},"content":[{"type":"text","text":"以 Serverless 的方式實現 Kubernetes 日誌告警"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/github.com\/OpenFunction\/samples","title":null,"type":null},"content":[{"type":"text","text":"OpenFunction Serverless Samples"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/github.com\/OpenFunction\/OpenFunction\/blob\/main\/docs\/concepts\/OpenFunction-events-framework.md","title":null,"type":null},"content":[{"type":"text","text":"OpenFunction Events Samples"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/openfunction.dev\/","title":null,"type":null},"content":[{"type":"text","text":"OpenFunction 官網"}],"marks":[{"type":"color","attrs":{"color":"#494949","name":"user"}}]}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"【編者按】"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"如果你有開源項目想要尋求報道,歡迎聯繫微信caifangfang842852(請註明姓名和來由)。"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章