Think Deep,Work Lean

2023-12-31-基于Openfaas实现Serverless云函数实战

Posted on By zack

前言

简单来讲云原生实践三步走:
上K8s容器化上servicemesh服务网格化上Serverless无服器化

什么是Serverless?价值在哪?为什么需要Serverless?

What

Serverless是什么?

Serverless直接翻译与理解就是“无服务器”。

那问题就来了,没有服务器,是不是就没有后端,那请求如何响应呢?

是不是觉得不可思议?

我们在理解一个事情的时候的直观感觉就是如果一个道理讲不清楚,经常会怀疑是不是在营造一个新的概念。毕竟现在太多的新名词。

其实从现象来看,当没有请求访问时,确实没有后端实例。但是当请求进来后,会快速拉起后端进行响应。如果请求流量过大,还会快速来扩容。如果请求降下来了,后端也会自动缩容。

这就是无服务器的本质,最大的商业价值,从老板角度是降本增效;从使用者即客户角度,就是可以实现按流量QPS付费,特别适合创业初期,没有服务器,但是想快速搭建出在线的服务的场景。

开源社区从Start上对比,openfaas比Knative高出一个数量级。openfaas可以部署到容器、k8s和虚机 2016年开源。文档没有knative好。此次我们针对Openfaas做一次实战。

环境搭建

本次环境搭建,用的是

centos7.8 k3s openfaas helm

# 安装k3s
curl -sfL https://get.k3s.io | sh - 
# Check for Ready node, takes ~30 seconds 
sudo k3s kubectl get node 

# 安装 faas-cli
curl -sSL https://cli.openfaas.com | sudo -E sh
#  标志 `-E` 允许将任何 `http_proxy` 环境变量传递到安装 bash 脚本。

# 安装 
# 安装helm
curl -sSLf https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
# 
kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/namespaces.yml
helm repo add openfaas https://openfaas.github.io/faas-netes/

# 由于是使用k3s,因此直接使用helm会报错,因此需要创建k8s的kubeconfig文件
cp /etc/rancher/k3s/k3s.yaml $HOME/.kube/config

helm repo update \
 && helm upgrade openfaas \
  --install openfaas/openfaas \
  --namespace openfaas

PASSWORD=$(kubectl -n openfaas get secret basic-auth -o jsonpath="{.data.basic-auth-password}" | base64 --decode) && \
echo "OpenFaaS admin password: $PASSWORD"

OpenFaaS admin password: Oo8S3RXTu61k

openfaas构建

faas-cli build # 构建docker镜像
faas-cli push # 推送镜像 
faas-cli deploy # 部署到k8s
faas-cli up # 一条命令等于上述三个命令的集合

模版

faas-cli template pull # 从官方github拉openfaas语言模版
faas-cli template store list # 模版商店查看有哪些模版
faas-cli template store pull go # 拉取go模版到本地
faas-cli template store pull openfaas/go # 也可以指定仓库
faas-cli template store describe go # 查看详细信息

实战:创建一个go的faas函数

# 拉取go模版,这个代码来源于 openFaas作者的书《everyday golang》中的案例
# 执行完后,会在本地生成一个tempalate目录,存放所有的模版,其中包含我们将要用的golang-middleware
faas-cli template store pull golang-middleware 
# 创建新函数
faas-cli new --lang golang-middleware echo

# 执行完后,生成对应的项目目录和配置文件:
[root@VM-0-12-centos ~]# ls
echo  echo.yml  template

[root@VM-0-12-centos ~]# tree echo
echo
├── go.mod
└── handler.go

至此已经生成了云函数,查看函数内容:

// 查看handler.go
package function

import (
        "fmt"
        "io"
        "net/http"
)

func Handle(w http.ResponseWriter, r *http.Request) {
        var input []byte

        if r.Body != nil {
                defer r.Body.Close()

                body, _ := io.ReadAll(r.Body)

                input = body
        }

        w.WriteHeader(http.StatusOK)
        w.Write([]byte(fmt.Sprintf("Body: %s", string(input))))
}

可以看到非常简单,不需要写server监听器相关的代码,只用关注自己业务逻辑的API函数即可。

这个函数非常简单,如果要加其他依赖、静态文件或是数据库,可以自行修改。

云函数也支持其他语言如:java node 等其他语言。具体参考 https://docs.openfaas.com/languages/go/

代码写完之后,需要打包成docker镜像并部署

# faas-cli up  -f echo.yml --skip-push
...
cc2447e1835a: Layer already exists
latest: digest: sha256:e30cae5f7963efc158d2cac8848bf49f27d3105013ebd65bda772586f26380a1 size: 1780
[0] < Pushing echo [zackzhangkai/openfaas-echo:latest] done.
[0] Worker done.
Deploying: echo.

Deployed. 202 Accepted.
URL: http://localhost:31112/function/echo

此时会报错需要Login,我们获取paasword及login

faas-cli login  # 用户名admin,密码 部署的时候有提示,也可以通过cm查询

PASSWORD=$(kubectl -n openfaas get secret basic-auth -o jsonpath="{.data.basic-auth-password}" | base64 --decode) && \
echo "OpenFaaS admin password: $PASSWORD"
[root@VM-0-12-centos ~]# kubectl -n openfaas get svc |grep gateway
gateway            ClusterIP   10.43.48.91     <none>        8080/TCP         4h41m
gateway-external   NodePort    10.43.61.133    <none>        8080:31112/TCP   4h41m
faas-cli login --gateway localhost:31112

可以看到函数已经部署出来了一个实例

[root@VM-0-12-centos ~]# kubectl get po -A | grep echo
openfaas-fn   echo-6459c9b577-wpx96                     1/1     Running     0               54s
[root@VM-0-12-centos ~]#

openfaas管控页面

openfaas自带管控页面,需要通过gateway查看登陆地址:

# kubectl get svc -A |grep gateway
openfaas      gateway                 ClusterIP      10.43.48.91     <none>        8080/TCP                     12d
openfaas      gateway-external        NodePort       10.43.61.133    <none>        8080:31112/TCP               12d

把svc暴露为nodePort,然后从页面上查看效果。

openfaas-ui

由于是serverless,所以具有弹性扩缩容,配置下即可

version: 1.0
provider:
  name: openfaas
  gateway: http://localhost:31112
functions:
  echo:
    lang: golang-middleware
    handler: ./echo
    image: zackzhangkai/openfaas-echo:latest
    labels: # 增加扩缩容的配置
      com.openfaas.scale.min: 1 # 最小只能是1
      com.openfaas.scale.max: 2 # 默认值是20
   com.openfaas.scale.zero: true # 是否缩到0,默认是false。社区版不支持缩到0

在实际生产环境中,需要配置环境变量、节点亲和性、给pod打label或是annotation等,都可以通过配置完成。

增加granfana大屏展示

通过上述步骤部署完openfaas后,会默认安装prometheus,此时将下列yaml apply到openfaas命名空间,即可以在页面上打开granfana:

# 用户名密码 admin/admin
apiVersion: apps/v1
kind: Deployment
metadata:
  name: grafana
  namespace: openfaas
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - name: grafana
        image: stefanprodan/faas-grafana:4.6.3
        ports:
        - containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
  name: grafana
  namespace: openfaas
spec:
  type: NodePort
  selector:
    app: grafana
  ports:
    - protocol: TCP
      port: 3000
      targetPort: 3000
      nodePort: 30000

查看所有的pod:

[root@VM-0-12-centos ~]# kubectl get po -A
NAMESPACE     NAME                                      READY   STATUS      RESTARTS      AGE
kube-system   coredns-6799fbcd5-fl84v                   1/1     Running     0             12d
kube-system   helm-install-traefik-crd-x2mlc            0/1     Completed   0             12d
kube-system   local-path-provisioner-84db5d44d9-4hdvz   1/1     Running     0             12d
kube-system   metrics-server-67c658944b-jr6qm           1/1     Running     0             12d
kube-system   helm-install-traefik-cwvj7                0/1     Completed   2             12d
kube-system   svclb-traefik-25c3b19a-tqf2d              2/2     Running     0             12d
kube-system   traefik-f4564c4f4-wkpxt                   1/1     Running     0             12d
openfaas      nats-5c48bc8b46-9vfg2                     1/1     Running     0             12d
openfaas      alertmanager-795bbdc56c-6m5sl             1/1     Running     0             12d
openfaas      gateway-67df8c4d4-zdd7t                   2/2     Running     1 (12d ago)   12d
openfaas      queue-worker-b9965cc56-t6p9d              1/1     Running     2 (12d ago)   12d
openfaas      prometheus-78d4c9f748-vstcb               1/1     Running     0             3d22h
openfaas      grafana-6c7949566-84pb6                   1/1     Running     0             3d22h
openfaas-fn   voice-wasm-serverless-7cdbd86dbc-vrrpq    1/1     Running     0             49m

页面上看到的效果:

openfaas-granfana