從同步函數 hello-world-dotnet 開始探索OpenFunction

OpenFunction[1] 是一個現代化的雲原生 FaaS(函數即服務)框架,它引入了很多非常優秀的開源技術棧,包括 Knative、Tekton、Shipwright、Dapr、KEDA 等,這些技術棧為打造新一代開源函數計算平台提供了無限可能:

  • Shipwright 可以在函數構建的過程中讓用戶自由選擇和切換鏡像構建的工具,並對其進行抽象,提供了統一的 API;
  • Knative 提供了優秀的同步函數運行時,具有強大的自動伸縮能力;
  • KEDA 可以基於更多類型的指標來自動伸縮,更加靈活;
  • Dapr 可以將不同應用的通用能力進行抽象,減輕開發分散式應用的工作量。

image

OpenFunction 最新發布了0.6版本,而且2022 年 4 月 27 日,OpenFunction[1] 順利通過了雲原生計算基金會 CNCF 技術監督委員會(TOC)的投票,正式進入 CNCF 沙箱(Sandbox)託管。OpenFunction 也將真正變成一個由 100% 社區驅動的開源項目。最近我也加入了OpenFunction項目開始規劃dotnet的支援開發,dotnet 框架支援的倉庫[2],目前完成0.1版本的開發。

經過我這2周時間的摸索,本文將會帶領大家快速部署和上手 OpenFunction,並通過一個 demo{hello-world-dotnet} 來體驗同步函數是如何運作的,以便對函數計算有一個感性的認知。

OpenFunction CLI 介紹

OpenFunction 從 0.5 版本開始使用全新的命令行工具 ofn[3] 來安裝各個依賴組件,它的功能更加全面,支援一鍵部署、一鍵卸載以及 Demo 演示的功能。用戶可以通過設置相應的參數自定義地選擇安裝各個組件,同時可以選擇特定的版本,使安裝更為靈活,安裝進程也提供了實時展示,使得介面更為美觀。它支援的組件和其依賴的 Kubernetes 版本如下:

image

ofn 的安裝參數 ofn install 解決了 OpenFunction 和 Kubernetes 的兼容問題,會自動根據 Kubernetes 版本選擇兼容組件進行安裝,同時提供多種參數以供用戶選擇。

image

使用 OpenFunction CLI 部署 OpenFunction

有了命令行工具 ofn 之後,OpenFunction 部署起來非常簡單。首先需要安裝 ofn,以 amd64 版本的 Linux 為例,僅需兩步即可:

1、下載 ofn,最新的ofn 是0.5.3

$ wget -c  //github.com/OpenFunction/cli/releases/download/v0.5.3/ofn_linux_amd64.tar.gz -O – | tar –xz

2、為 ofn 賦予許可權並移動到 /usr/local/bin/ 文件夾下。

$ chmod +x ofn && mv ofn /usr/local/bin/

安裝好 ofn 之後,僅需一步即可完成 OpenFunction 的安裝。雖然使用 --all 選項可以安裝所有組件,也可以選擇安裝指定需要安裝的組件,我們的集群裡面已經安裝了Dapr的情況下,我們就不想額外安裝一遍Dapr ,不過如果集群裡面已經安裝了Dapr的情況下他也不會給重新安裝的,具體可以看下圖。

image

安裝成功了,之後我們就可以開始運行同步函數了,OpenFunction 還支援非同步函數,這部分今天就不演示了,留作後續在dotnet框架裡面實現了非同步函數的時候再來。

同步函數 demo 示例

OpenFunction 官方倉庫提供了多種語言的同步函數示例[4]

image

這裡我們選擇 dotnet 的函數示例,先來看一下最核心的部署清單:

apiVersion: core.openfunction.io/v1beta1
kind: Function
metadata:
   name: dotnet-sample
   namespace: default
spec:
   version: “v1.0.0”
   image: “geffzhang/sample-dotnet-func:v1”
   imageCredentials:
     name: push-secret
   port: 8080 # default to 8080
   build:
     builder: “openfunction/gcp-builder:v1”
     env:
       GOOGLE_FUNCTION_TARGET: “helloworld”
       GOOGLE_FUNCTION_SIGNATURE_TYPE: “http”
     srcRepo:
       url: “//github.com/openfunction/samples.git”
       sourceSubPath: “functions/knative/hello-world-dotnet”
       revision: “release-0.6”
   serving:
     runtime: “knative” # default to knative
     template:
       containers:
         – name: function
           imagePullPolicy: IfNotPresent

Function 是由 CRD 定義的一個 CR,用來將函數轉換為最終運行的應用。這個例子裡面包含了兩個組件:

  • build : 通過 Shipwright 選擇不同的鏡像構建工具,最終將應用構建為容器鏡像;
  • Serving : 通過 Serving CRD 將應用部署到不同的運行時中,可以選擇同步運行時或非同步運行時。這裡選擇的是同步運行時 knative。

運行這個示例之前,需要在運行函數的命名空間下創建Secret ,生成一個Secret 來訪問您的容器註冊表,例如Docker Hub[5]Quay.io[6] 上的一個。這一點非常重要,不然就在Build 階段就失敗了

REGISTRY_SERVER您可以通過編輯以下命令中的REGISTRY_USER和欄位來創建此密鑰REGISTRY_PASSWORD,然後運行它。

REGISTRY_SERVER=//index.docker.io/v1/ REGISTRY_USER= < your_registry_user > REGISTRY_PASSWORD= < your_registry_password >
kubectl create secret –n default docker-registry push-secret \
     –docker-server= $REGISTRY_SERVER \
     –docker-username= $REGISTRY_USER \
     –docker-password= $REGISTRY_PASSWORD

然後將上面的部署清單保存為function-dotnet-sample.yaml ,修改spec.image 欄位為您自己的容器註冊表地址,使用以下命令創建此函數:

kubectl apply –f  function-dotnet-sample.yaml

在Build 階段,builder會啟動一個 Pod 來構建鏡像,這個 Pod 中包含了 4 個容器:

  • step-source-default : 拉取源程式碼;
  • step-prepare : 設置環境變數;
  • step-create : 構建鏡像;
  • step-results : 輸出鏡像的 digest。

您可以使用以下命令觀察函數的過程。

kubectl get functions -n default

NAME              BUILDSTATE   SERVINGSTATE   BUILDER         SERVING         URL                                              AGE
dotnet-sample     Succeeded    Running        builder-hf74t   serving-wh6hs   //openfunction.io/default/dotnet-sample     54m

URL是OpenFunction Domain提供的可以訪問的地址。要通過此 URL 地址訪問該功能,您需要確保 DNS 可以解析此地址。使用以下命令在集群中創建一個 pod,並從該 pod 訪問該功能

kubectl run  curl –image=radial/busyboxplus:curl -i –tty

[ root@curl:/ ]$ curl //openfunction.io.svc.cluster.local/default/dotnet-sample/

還可以通過 Knative Services 提供的訪問地址觸發該功能

kubectl get ksvc

geffzhang@edgevm1:~/openfunctionsamples/functions/knative/hello-world-dotnet$ sudo kubectl get ksvc
NAME                       URL                                                               LATESTCREATED                   LATESTREADY                     READY   REASON
serving-wh6hs-ksvc-m7fc9   //serving-wh6hs-ksvc-m7fc9.default.20.239.115.228.sslip.io   serving-wh6hs-ksvc-m7fc9-v100   serving-wh6hs-ksvc-m7fc9-v100   True

這個地址是可以直接訪問的

image

訪問這個函數時會自動觸發運行一個 Pod:

image

這個 Pod 使用的鏡像就是之前 build 階段構建的鏡像。事實上這個 Pod 是由 Deployment 控制的,在沒有流量時,這個 Deployment 的副本數是 0。當有新的流量進入時,會先進入 Knative 的 Activator,Activator 接收到流量後會通知 Autoscaler(自動伸縮控制器),然後 Autoscaler 將 Deployment 的副本數擴展到 1,最後 Activator 會將流量轉發到實際的 Pod 中,從而實現服務調用。這個過程也叫冷啟動

如果你不再訪問這個入口,過一段時間之後,Deployment 的副本數就會被收縮為 0:

image

通過上面的示例,相信大家應該能夠體會到一些函數計算的優勢,我們只需要專註於業務開發,編寫函數程式碼,並上傳到程式碼倉庫,其他的東西不需要關心,就連Dockerfile都不需要編寫,不需要了解基礎設施,甚至不需要知道容器和 Kubernetes 的存在。函數計算平台會自動為您分配好計算資源,並彈性地運行任務,只有當您需要訪問的時候,才會通過擴容來運行任務,其他時間並不會消耗計算資源,可以充分利用dotnet在雲原生時代的優勢,使用dotnet寫函數是很高效的,大家可以體驗一下我上面的示例//serving-wh6hs-ksvc-m7fc9.default.20.239.115.228.sslip.io 。OpenFunction基於Dapr 所提供的各種分散式能力,讓我們輕鬆的實現無服務微服務架構,獲得像Azure 容器應用[7] 一樣的能力。

相關鏈接

[1] openFunction: //github.com/OpenFunction/OpenFunction

[2] functions-framework-dotnet: //github.com/OpenFunction/functions-framework-dotnet

[3] ofn: //github.com/OpenFunction/cli

[4] OpenFunction 官方倉庫提供了多種語言的同步函數示例:  //github.com/OpenFunction/samples/tree/main/functions/knative

[5] Docker Hub: //hub.docker.com/

[6] Quay.io: //quay.io/

[7] Azure 容器應用: //www.cnblogs.com/shanyou/p/15509042.html