
OpenFunction 0.6.0 上周已經正式發布了,帶來了許多值得注意的功能,包括函式插件、函式的分布式跟蹤、控制自動縮放、HTTP 函式觸發異步函式等,同時,異步運行時定義也被重構了,核心 API 也已經從 v1alpha1 升級到 v1beta1,
官宣鏈接??:https://openfunction.dev/blog/2022/03/25/announcing-openfunction-0.6.0-faas-observability-http-trigger-and-more/
近年來,隨著無服務器計算的興起,出現了很多非常優秀的 Serverless 開源專案,其中比較杰出的有 Knative 和 OpenFaaS,但 Knative Serving 僅僅能運行應用,還不能運行函式,而 Serverless 的核心是函式計算,也就是 FaaS,因此比較遺憾;OpenFaaS 雖然很早就出圈了,但技術堆疊過于老舊,不能滿足現代化函式計算平臺的需求,
OpenFunction 便是這樣一個現代化的云原生 FaaS(函式即服務)框架,它引入了很多非常優秀的開源技術堆疊,包括 Knative、Tekton、Shipwright、Dapr、KEDA 等,這些技術堆疊為打造新一代開源函式計算平臺提供了無限可能:
- Shipwright 可以在函式構建的程序中讓用戶自由選擇和切換鏡像構建的工具,并對其進行抽象,提供了統一的 API;
- Knative 提供了優秀的同步函式運行時,具有強大的自動伸縮能力;
- KEDA 可以基于更多型別的指標來自動伸縮,更加靈活;
- Dapr 可以將不同應用的通用能力進行抽象,減輕開發分布式應用的作業量,

本文不打算講一些非常高深的理論,作為剛跨進 Serverless 門檻的用戶,更需要的是如何快速上手,以便對函式計算有一個感性的認知,在后續使用的程序中,咱們再慢慢理解其中的架構和設計,
本文將會帶領大家快速部署和上手 OpenFunction,并通過一個 demo 來體驗同步函式是如何運作的,
OpenFunction CLI 介紹
OpenFunction 從 0.5 版本開始使用全新的命令列工具 ofn 來安裝各個依賴組件,它的功能更加全面,支持一鍵部署、一鍵卸載以及 Demo 演示的功能,用戶可以通過設定相應的引數自定義地選擇安裝各個組件,同時可以選擇特定的版本,使安裝更為靈活,安裝行程也提供了實時展示,使得界面更為美觀,它支持的組件和其依賴的 Kubernetes 版本如下:
| Components | Kubernetes 1.17 | Kubernetes 1.18 | Kubernetes 1.19 | Kubernetes 1.20+ |
|---|---|---|---|---|
| Knative Serving | 0.21.1 | 0.23.3 | 0.25.2 | 1.0.1 |
| Kourier | 0.21.0 | 0.23.0 | 0.25.0 | 1.0.1 |
| Serving Default Domain | 0.21.0 | 0.23.0 | 0.25.0 | 1.0.1 |
| Dapr | 1.5.1 | 1.5.1 | 1.5.1 | 1.5.1 |
| Keda | 2.4.0 | 2.4.0 | 2.4.0 | 2.4.0 |
| Shipwright | 0.6.1 | 0.6.1 | 0.6.1 | 0.6.1 |
| Tekton Pipelines | 0.23.0 | 0.26.0 | 0.29.0 | 0.30.0 |
| Cert Manager | 1.5.4 | 1.5.4 | 1.5.4 | 1.5.4 |
| Ingress Nginx | na | na | 1.1.0 | 1.1.0 |
ofn 的安裝引數 `ofn install` 解決了 OpenFunction 和 Kubernetes 的兼容問題,會自動根據 Kubernetes 版本選擇兼容組件進行安裝,同時提供多種引數以供用戶選擇,
| 引數 | 功能 |
|---|---|
| --all | 用于安裝 OpenFunction 及其所有依賴, |
| --async | 用于安裝 OpenFunction 的異步運行時(Dapr & Keda), |
| --cert-manager * | 用于安裝 Cert Manager, |
| --dapr * | 用于安裝 Dapr, |
| --dry-run | 用于提示當前命令所要安裝的組件及其版本, |
| --ingress * | 用于安裝 Ingress Nginx, |
| --keda * | 用于安裝 Keda, |
| --knative | 用于安裝 Knative Serving(以Kourier為默認網關) |
| --region-cn | 針對訪問 gcr.io 或 github.com 受限的用戶, |
| --shipwright * | 用于安裝 ShipWright, |
| --sync | 用于安裝 OpenFunction Sync Runtime(待支持), |
| --upgrade | 在安裝時將組件升級到目標版本, |
| --verbose | 顯示粗略資訊, |
| --version | 用于指定要安裝的 OpenFunction 的版本,(默認為 "v0.6.0") |
| --timeout | 設定超時時間,默認為5分鐘, |
使用 OpenFunction CLI 部署 OpenFunction
有了命令列工具 ofn 之后,OpenFunction 部署起來非常簡單,首先需要安裝 ofn,以 amd64 版本的 Linux 為例,僅需兩步即可:
1、下載 ofn
$ wget -c https://github.com/OpenFunction/cli/releases/download/v0.5.1/ofn_linux_amd64.tar.gz -O - | tar -xz
2、為 ofn 賦予權限并移動到 /usr/local/bin/ 檔案夾下,
$ chmod +x ofn && mv ofn /usr/local/bin/
安裝好 ofn 之后,僅需一步即可完成 OpenFunction 的安裝,雖然使用 --all 選項可以安裝所有組件,但我知道大部分小伙伴的真實需求是不想再額外裝一下 Ingress Controller 的,這個也好辦,我們可以直接指定需要安裝的組件,排除 ingress,命令如下:
$ ofn install --knative --async --shipwright --cert-manager --region-cn
Start installing OpenFunction and its dependencies.
The following components will be installed:
+------------------+---------+
| COMPONENT | VERSION |
+------------------+---------+
| OpenFunction | 0.6.0 |
| Keda | 2.4.0 |
| Dapr | 1.5.1 |
| Shipwright | 0.6.1 |
| CertManager | 1.5.4 |
| Kourier | 1.0.1 |
| DefaultDomain | 1.0.1 |
| Knative Serving | 1.0.1 |
| Tekton Pipelines | 0.30.0 |
+------------------+---------+
? Dapr - Completed!
? Keda - Completed!
? Knative Serving - Completed!
? Shipwright - Completed!
? Cert Manager - Completed!
? OpenFunction - Completed!
?? Completed in 2m47.901328069s.
██████╗ ██████╗ ███████╗███╗ ██╗
██╔═══██╗██╔══██╗██╔════╝████╗ ██║
██║ ██║██████╔╝█████╗ ██╔██╗ ██║
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║
╚██████╔╝██║ ███████╗██║ ╚████║
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝
███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
█████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
雖然本文演示的是同步函式,但這里把異步運行時也裝上了,如果你不需要,可以把 --async 這個引數去掉,不影響本文的實驗,
安裝完成后,會創建這幾個 namespace:
$ kubectl get ns
NAME STATUS AGE
cert-manager Active 17m
dapr-system Active 4m34s
io Active 3m31s
keda Active 4m49s
knative-serving Active 4m41s
kourier-system Active 3m57s
openfunction Active 3m37s
shipwright-build Active 4m26s
tekton-pipelines Active 4m50s
每個 namespace 對應上面安裝的各個組件,目前 OpenFunction 的 Webhook 需要使用 CertManager 來驗證 API 訪問,后續我們會去掉這個依賴,不再需要安裝 CertManager,
自定義域名后綴
Knative Serving 目前使用 Kourier 作為入口網關,由于我們沒有部署 Ingress Controller,所以我們訪問函式只有 Kourier 這一個入口,
Kourier 是一個基于 Envoy Proxy 的輕量級網關,是專門對于 Knative Serving 服務訪問提供的一個網關實作,關于 Envoy 控制平面的細節本文不作贅述,感興趣的可以去閱讀 Kourier 官方檔案和原始碼,這里我們只需要知道 Kourier 會為函式訪問提供一個入口,這個訪問入口是通過域名來提供的,我們要做的作業就是將相關域名決議到 Kourier 的 ClusterIP,
Kourier 默認創建了兩個 Service:
$ kubectl -n kourier-system get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kourier LoadBalancer 10.233.7.202 <pending> 80:31655/TCP,443:30980/TCP 36m
kourier-internal ClusterIP 10.233.47.71 <none> 80/TCP 36m
只需要將與函式訪問相關域名決議到 10.233.47.71 即可,
雖然每個函式的域名都是不同的,但域名后綴是一樣的,可以通過泛域名決議來實作決議與函式相關的所有域名,Kourier 默認的域名后綴是 example.com,通過 Knative 的 ConfigMap config-domain 來配置:
$ kubectl -n knative-serving get cm config-domain -o yaml
apiVersion: v1
data:
_example: |
################################
# #
# EXAMPLE CONFIGURATION #
# #
################################
# This block is not actually functional configuration,
# but serves to illustrate the available configuration
# options and document them in a way that is accessible
# to users that `kubectl edit` this config map.
#
# These sample configuration options may be copied out of
# this example block and unindented to be in the data block
# to actually change the configuration.
# Default value for domain.
# Although it will match all routes, it is the least-specific rule so it
# will only be used if no other domain matches.
example.com: |
# These are example settings of domain.
# example.org will be used for routes having app=nonprofit.
example.org: |
selector:
app: nonprofit
# Routes having the cluster domain suffix (by default 'svc.cluster.local')
# will not be exposed through Ingress. You can define your own label
# selector to assign that domain suffix to your Route here, or you can set
# the label
# "networking.knative.dev/visibility=cluster-local"
# to achieve the same effect. This shows how to make routes having
# the label app=secret only exposed to the local cluster.
svc.cluster.local: |
selector:
app: secret
kind: ConfigMap
metadata:
annotations:
knative.dev/example-checksum: 81552d0b
labels:
app.kubernetes.io/part-of: knative-serving
app.kubernetes.io/version: 1.0.1
serving.knative.dev/release: v1.0.1
name: config-domain
namespace: knative-serving
將其中的 _example 物件洗掉,添加一個默認域名(例如 openfunction.dev),最終修改結果如下:
$ kubectl -n knative-serving get cm config-domain -o yaml
apiVersion: v1
data:
openfunction.dev: ""
kind: ConfigMap
metadata:
annotations:
knative.dev/example-checksum: 81552d0b
labels:
app.kubernetes.io/part-of: knative-serving
app.kubernetes.io/version: 1.0.1
serving.knative.dev/release: v1.0.1
name: config-domain
namespace: knative-serving
配置集群域名決議
為了便于在 Kubernetes 的 Pod 中訪問函式,可以對 Kubernetes 集群的 CoreDNS 進行改造,使其能夠對域名后綴 openfunction.dev 進行泛決議,需要在 CoreDNS 的配置中添加一段內容:
template IN A openfunction.dev {
match .*\.openfunction\.dev
answer "{{ .Name }} 60 IN A 10.233.47.71"
fallthrough
}
修改完成后的 CoreDNS 配置如下:
$ kubectl -n kube-system get cm coredns -o yaml
apiVersion: v1
data:
Corefile: |
.:53 {
errors
health
ready
template IN A openfunction.dev {
match .*\.openfunction\.dev
answer "{{ .Name }} 60 IN A 10.233.47.71"
fallthrough
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
}
hosts /etc/coredns/NodeHosts {
ttl 60
reload 15s
fallthrough
}
prometheus :9153
forward . /etc/resolv.conf
cache 30
loop
reload
loadbalance
}
...
同步函式 demo 示例
配置完域名決議后,接下來可以運行一個同步函式的示例來驗證一下,OpenFunction 官方倉庫提供了多種語言的同步函式示例:

這里我們選擇 Go 語言的函式示例,先來看一下最核心的部署清單:
# function-sample.yaml
apiVersion: core.openfunction.io/v1beta1
kind: Function
metadata:
name: function-sample
spec:
version: "v2.0.0"
image: "openfunctiondev/sample-go-func:latest"
imageCredentials:
name: push-secret
port: 8080 # default to 8080
build:
builder: openfunction/builder-go:latest
env:
FUNC_NAME: "HelloWorld"
FUNC_CLEAR_SOURCE: "true"
srcRepo:
url: "https://github.com/OpenFunction/samples.git"
sourceSubPath: "functions/knative/hello-world-go"
revision: "main"
serving:
template:
containers:
- name: function
imagePullPolicy: Always
runtime: "knative"
Function 是由 CRD 定義的一個 CR,用來將函式轉換為最終運行的應用,這個例子里面包含了兩個組件:
- build : 通過 Shipwright 選擇不同的鏡像構建工具,最終將應用構建為容器鏡像;
- Serving : 通過 Serving CRD 將應用部署到不同的運行時中,可以選擇同步運行時或異步運行時,這里選擇的是同步運行時 knative,
國內環境由于不可抗因素,可以通過 GOPROXY 從公共代理鏡像中快速拉取所需的依賴代碼,只需在部署清單中的 build 階段添加一個環境變數 FUNC_GOPROXY 即可:
# function-sample.yaml
apiVersion: core.openfunction.io/v1beta1
kind: Function
metadata:
name: function-sample
spec:
version: "v2.0.0"
image: "openfunctiondev/sample-go-func:latest"
imageCredentials:
name: push-secret
port: 8080 # default to 8080
build:
builder: openfunction/builder-go:latest
env:
FUNC_NAME: "HelloWorld"
FUNC_CLEAR_SOURCE: "true"
FUNC_GOPROXY: "https://proxy.golang.com.cn,direct"
srcRepo:
url: "https://github.com/OpenFunction/samples.git"
sourceSubPath: "functions/knative/hello-world-go"
revision: "main"
serving:
template:
containers:
- name: function
imagePullPolicy: Always
runtime: "knative"
在創建函式之前,需要先創建一個 secret 來存盤 Docker Hub 的用戶名和密碼:
$ REGISTRY_SERVER=https://index.docker.io/v1/ REGISTRY_USER=<your_registry_user> REGISTRY_PASSWORD=<your_registry_password>
$ kubectl create secret docker-registry push-secret \
--docker-server=$REGISTRY_SERVER \
--docker-username=$REGISTRY_USER \
--docker-password=$REGISTRY_PASSWORD
下面通過 kubectl 創建這個 Function:
$ kubectl apply -f function-sample.yaml
查看 Function 運行狀況:
$ kubectl get function
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING URL AGE
function-sample Building builder-6ht76 5s
目前正處于 Build 階段,builder 的名稱是 builder-6ht76,查看 builder 的運行狀態:
$ kubectl get builder
NAME PHASE STATE REASON AGE
builder-6ht76 Build Building 50s
這個 builder 會啟動一個 Pod 來構建鏡像:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
builder-6ht76-buildrun-jvtwk-vjlgt-pod 2/4 NotReady 0 2m11s
這個 Pod 中包含了 4 個容器:
-
step-source-default : 拉取源代碼;

-
step-prepare : 設定環境變數;

-
step-create : 構建鏡像;

-
step-results : 輸出鏡像的 digest,
再次查看函式狀態:
$ kubectl get function
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING URL AGE
function-sample Succeeded Running builder-6ht76 serving-6w4rn http://openfunction.io/default/function-sample 6m
已經由之前的 Building 狀態變成了 Runing 狀態,
這里的 URL 我們無法直接訪問,因為沒有部署 Ingress Controller,不過我們可以通過其他方式來訪問,Kourier 把每個訪問入口抽象為一個 CR 叫 ksvc,每一個 ksvc 對應一個函式的訪問入口,可以看下目前有沒有創建 ksvc:
$ kubectl get ksvc
NAME URL LATESTCREATED LATESTREADY READY REASON
serving-6w4rn-ksvc-k4x29 http://serving-6w4rn-ksvc-k4x29.default.openfunction.dev serving-6w4rn-ksvc-k4x29-v200 serving-6w4rn-ksvc-k4x29-v200 True
函式的訪問入口就是 http://serving-6w4rn-ksvc-k4x29.default.openfunction.dev,由于在前面的章節中已經配置好了域名決議,這里可以啟動一個 Pod 來直接訪問該域名:
$ kubectl run curl --image=radial/busyboxplus:curl -i --tty
If you don't see a command prompt, try pressing enter.
[ root@curl:/ ]$
[ root@curl:/ ]$ curl http://serving-6w4rn-ksvc-k4x29.default.openfunction.dev/default/function-sample/World
Hello, default/function-sample/World!
[ root@curl:/ ]$ curl http://serving-6w4rn-ksvc-k4x29.default.openfunction.dev/default/function-sample/OpenFunction
Hello, default/function-sample/OpenFunction!
訪問這個函式時會自動觸發運行一個 Pod:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
serving-6w4rn-ksvc-k4x29-v200-deployment-688d58bfb-6fvcg 2/2 Running 0 7s
這個 Pod 使用的鏡像就是之前 build 階段構建的鏡像,事實上這個 Pod 是由 Deployment 控制的,在沒有流量時,這個 Deployment 的副本數是 0,當有新的流量進入時,會先進入 Knative 的 Activator,Activator 接收到流量后會通知 Autoscaler(自動伸縮控制器),然后 Autoscaler 將 Deployment 的副本數擴展到 1,最后 Activator 會將流量轉發到實際的 Pod 中,從而實作服務呼叫,這個程序也叫冷啟動,
如果你不再訪問這個入口,過一段時間之后,Deployment 的副本數就會被收縮為 0:
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
serving-6w4rn-ksvc-k4x29-v200-deployment 0/0 0 0 22m
總結
通過本文的示例,相信大家應該能夠體會到一些函式計算的優勢,它為我們帶來了我們所期望的對業務場景快速拆解重構的能力,作為用戶,只需要專注于他們的開發意圖,撰寫函式代碼,并上傳到代碼倉庫,其他的東西不需要關心,不需要了解基礎設施,甚至不需要知道容器和 Kubernetes 的存在,函式計算平臺會自動為您分配好計算資源,并彈性地運行任務,只有當您需要訪問的時候,才會通過擴容來運行任務,其他時間并不會消耗計算資源,
本文由博客一文多發平臺 OpenWrite 發布!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/455403.html
標籤:其他
上一篇:SQL創建一個新列而不是新行
