OpenFunction 0.6.0 was officially released last week, bringing many notable features including function plugins, distributed tracing of functions, control of autoscaling, HTTP functions triggering asynchronous functions, and more. At the same time, the asynchronous runtime definition has also been refactored. The core API has also been upgraded from v1alpha1 to v1beta1.
Official announcement link🔗: https://openfunction.dev/blog/2022/03/25/announcing-openfunction-0.6.0-faas-observability-http-trigger-and-more/
In recent years, with the rise of serverless computing , there have been many excellent Serverless open source projects, among which Knative and OpenFaaS are more outstanding. However, Knative Serving can only run applications, not functions, and the core of Serverless is function computing, which is FaaS, so it is a pity; although OpenFaaS has been out of the circle for a long time, its technology stack is too old to meet modern function computing. platform needs.
OpenFunction is such a modern cloud-native FaaS (Function as a Service) framework. It introduces many excellent open source technology stacks, including Knative, Tekton, Shipwright, Dapr, KEDA, etc. These technology stacks are used to create a new generation of open source function computing. The platform offers endless possibilities:
- Shipwright allows users to freely select and switch image building tools in the process of function construction, and abstracts them to provide a unified API;
- Knative provides an excellent synchronous function runtime with powerful automatic scaling capabilities;
- KEDA can automatically scale based on more types of indicators, making it more flexible;
- Dapr can abstract the general capabilities of different applications and reduce the workload of developing distributed applications.
This article is not going to talk about some very advanced theories. As a user who has just stepped into the serverless threshold, what is more needed is how to get started quickly, so as to have a perceptual understanding of function computing. In the process of subsequent use, we will slowly understand it. The architecture and design of it.
This article will lead you to quickly deploy and get started with OpenFunction, and experience how the synchronization function works through a demo.
Introduction to OpenFunction CLI
Since version 0.5, OpenFunction uses a new command-line tool ofn to install each dependent component. It has more comprehensive functions and supports one-click deployment, one-click uninstallation, and demo demonstration functions. Users can customize and install each component by setting the corresponding parameters, and can choose a specific version to make the installation more flexible. The installation process also provides real-time display, making the interface more beautiful. The components it supports and the Kubernetes versions it depends on are as follows:
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 |
<center>Table 1 The Kubernetes version that the third-party components used by OpenFunction depend on</center>
The installation parameter of ofn install
solves the compatibility problem between OpenFunction and Kubernetes, and automatically selects compatible components for installation according to the Kubernetes version, and provides various parameters for users to choose.
parameter | Function |
---|---|
--all | Used to install OpenFunction and all its dependencies. |
--async | Asynchronous runtime (Dapr & Keda) for installing OpenFunction. |
--cert-manager * | Used to install Cert Manager. |
--dapr * | Used to install Dapr. |
--dry-run | Used to prompt the current command to install the components and their versions. |
--ingress * | Used to install Ingress Nginx. |
--keda* | Used to install Keda. |
--knative | Used to install Knative Serving (with Kourier as the default gateway) |
--region-cn | For users with limited access to gcr.io or github.com. |
--shipwright * | Used to install ShipWright. |
--sync | Used to install OpenFunction Sync Runtime (to be supported). |
--upgrade | Upgrade components to the target version at install time. |
--verbose | Displays rough information. |
--version | Used to specify the version of OpenFunction to install. (default "v0.6.0") |
--timeout | Set the timeout period. The default is 5 minutes. |
<center>Table II install command parameter list</center>
Deploy OpenFunction using OpenFunction CLI
With the command line tool ofn, OpenFunction is very simple to deploy. First of all, you need to install ofn. Taking the amd64 version of Linux as an example, it only takes two steps:
1. Download ofn
$ wget -c https://github.com/OpenFunction/cli/releases/download/v0.5.1/ofn_linux_amd64.tar.gz -O - | tar -xz
2. Grant permissions to ofn and move to the /usr/local/bin/
folder.
$ chmod +x ofn && mv ofn /usr/local/bin/
Once ofn is installed, OpenFunction can be installed in just one step. Although all components can be installed by using the --all
option, I know that most of my friends do not want to install an additional Ingress Controller. ingress, the command is as follows:
$ 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.
██████╗ ██████╗ ███████╗███╗ ██╗
██╔═══██╗██╔══██╗██╔════╝████╗ ██║
██║ ██║██████╔╝█████╗ ██╔██╗ ██║
██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║
╚██████╔╝██║ ███████╗██║ ╚████║
╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝
███████╗██╗ ██╗███╗ ██╗ ██████╗████████╗██╗ ██████╗ ███╗ ██╗
██╔════╝██║ ██║████╗ ██║██╔════╝╚══██╔══╝██║██╔═══██╗████╗ ██║
█████╗ ██║ ██║██╔██╗ ██║██║ ██║ ██║██║ ██║██╔██╗ ██║
██╔══╝ ██║ ██║██║╚██╗██║██║ ██║ ██║██║ ██║██║╚██╗██║
██║ ╚██████╔╝██║ ╚████║╚██████╗ ██║ ██║╚██████╔╝██║ ╚████║
╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝
Although this article demonstrates the synchronous function, the asynchronous runtime is also installed here. If you don't need it, you can remove the --async
parameter, which does not affect the experiment in this article.
After the installation is complete, these namespaces will be created:
$ 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
Each namespace corresponds to each component installed above. Currently, OpenFunction's Webhook needs to use CertManager to verify API access. We will remove this dependency in the future and no longer need to install CertManager .
custom domain suffix
Knative Serving currently uses Kourier
as the ingress gateway. Since we have not deployed the Ingress Controller, we only have access to the function Kourier
this entry.
Kourier is a lightweight gateway based on Envoy Proxy , a gateway implementation specially provided for Knative Serving service access. The details of the Envoy control plane will not be repeated in this article. If you are interested, you can read the official documentation and source code of Kourier. Here we only need to know that Kourier will provide an entry for function access. This access entry is provided through the domain name. What we need to do is to resolve the relevant domain name to the ClusterIP of Kourier.
Kourier creates two Services by default:
$ 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
Just resolve the domain name related to function access to 10.233.47.71
.
Although the domain name of each function is different, the domain name suffix is the same, and pan-domain name resolution can be used to resolve all domain names related to the function. The default domain name suffix of Kourier is example.com
, which is configured through Knative's 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
Delete the _example
object and add a default domain name (such as openfunction.dev
), the final modification result is as follows:
$ 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
Configure cluster domain name resolution
In order to facilitate access to functions in the Pod of Kubernetes, the CoreDNS of the Kubernetes cluster can be modified to enable the domain name suffix openfunction.dev
to perform pan-resolution, and you need to add a paragraph to the CoreDNS configuration:
template IN A openfunction.dev {
match .*\.openfunction\.dev
answer "{{ .Name }} 60 IN A 10.233.47.71"
fallthrough
}
The modified CoreDNS configuration is as follows:
$ 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
}
...
Synchronous function demo example
After configuring domain name resolution, you can run an example of a synchronous function to verify it. The OpenFunction official repository provides examples of synchronization functions in multiple languages :
Here we choose the function example of the Go language, let's take a look at the core deployment list first:
# 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
is a CR defined by the CRD to convert the function into the final running application. This example contains two components:
- build : Select different image building tools through Shipwright, and finally build the application as a container image;
- Serving : Deploy applications to different runtimes through Serving CRD, you can choose synchronous runtime or asynchronous runtime. The synchronous runtime knative is chosen here.
Due to force majeure factors in the domestic environment, you can quickly pull the required dependency code from the public proxy image through GOPROXY
, just add an environment variable in the FUNC_GOPROXY
build
stage in the deployment list- FUNC_GOPROXY
can:
# 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"
Before creating the function, you need to create a secret to store your Docker Hub username and password:
$ 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
Let's create this Function with kubectl:
$ kubectl apply -f function-sample.yaml
Check Function health:
$ kubectl get function
NAME BUILDSTATE SERVINGSTATE BUILDER SERVING URL AGE
function-sample Building builder-6ht76 5s
Currently in the Build stage, the name of the builder is builder-6ht76
. Check the running status of the builder:
$ kubectl get builder
NAME PHASE STATE REASON AGE
builder-6ht76 Build Building 50s
This builder will start a Pod to build the image:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
builder-6ht76-buildrun-jvtwk-vjlgt-pod 2/4 NotReady 0 2m11s
This Pod contains 4 containers:
step-source-default : pull source code;
step-prepare : set environment variables;
step-create : build the image;
- step-results : Digest of the output image.
Check the function status again:
$ 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
It has changed from the previous Building state to the Running state.
The URL here we cannot access directly because there is no Ingress Controller deployed. However, we can access it in other ways. Kourier abstracts each access entry into a CR called ksvc . Each ksvc corresponds to the access entry of a function. You can see if ksvc is currently created:
$ 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
The access entry of the function is http://serving-6w4rn-ksvc-k4x29.default.openfunction.dev . Since the domain name resolution has been configured in the previous chapter, you can start a Pod to access the domain name directly:
$ 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!
Accessing this function will automatically trigger a Pod to run:
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
serving-6w4rn-ksvc-k4x29-v200-deployment-688d58bfb-6fvcg 2/2 Running 0 7s
The image used by this Pod is the image built in the previous build phase. In fact, this Pod is controlled by the Deployment. When there is no traffic, the number of copies of this Deployment is 0. When new traffic enters, it will first enter the Activator of Knative. After the Activator receives the traffic, it will notify the Autoscaler (automatic scaling controller), then the Autoscaler will expand the number of copies of the Deployment to 1, and finally the Activator will forward the traffic to the actual Pod to implement service calls. This process is also called a cold start .
If you no longer access this entry, after a period of time, the number of replicas of the Deployment will be shrunk to 0:
$ kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
serving-6w4rn-ksvc-k4x29-v200-deployment 0/0 0 0 22m
Summarize
Through the examples in this article, I believe that everyone should be able to appreciate some advantages of function computing, which brings us the ability to quickly disassemble and reconstruct business scenarios that we expect. As a user, you only need to focus on their development intentions, write functional code, and upload it to the code repository. You don't need to care about other things, you don't need to know about the infrastructure, and you don't even need to know the existence of containers and Kubernetes. The function computing platform will automatically allocate computing resources for you, and run tasks flexibly. Only when you need access, will you run tasks through capacity expansion, and will not consume computing resources at other times.
This article is published by OpenWrite , a multi-post blog platform!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。