理解FaaS & OpenFaaS部署
潘忠显 / 2021-03-26
最近在了解和学习使用FaaS,其中的一些理解和实践过程,在这里做简单的笔记。理解不对的,请不吝指正。
一、FaaS是什么?
-
FaaS (Function-as-a-Service,函数即服务)
-
一种云计算服务
-
FaaS是Serverless(无服务器计算)的子集
-
F/Function 是一小段具有完整功能的代码
-
事件驱动,运行代码以响应事件
-
使用者专注于开发功能函数,无需关注部署,FaaS框架会管理内存、CPU、网络和其他资源均衡的计算机群
-
每个函数有单独的版本
1. 与Serverless的关系
Serverless 和 FaaS 通常相互混淆,实际上FaaS是Serverless的子集。CNCF的白皮书中提到:
Serverless计算平台能够提供FaaS或/和BaaS。
Serverless专注于任何服务类别,包括计算、存储、数据库、消息传递、API网关等,对用户屏蔽了服务器的配置、管理和计费。
而FaaS是Serverless架构中的核心技术,但它专注于事件驱动的计算范例,仅当需要响应事件或请求时,应用程序代码或容器才会运行。
2. 与微服务的对比
接口形式类似微服务类似。微服务将服务拆解成更小的服务(函数集合),然后打到镜像,运行在容器上。这些容器的维护和扩缩容,仍然需要服务提供者自己去关心。
FaaS是微服务更进一步,会将服务拆成单个的函数,每个函数部署在FaaS平台,平台会规范函数、扩缩容、打补丁、维护环境。
3. 与PaaS的区别
FaaS变更时间更短,在毫秒几倍。
对于FaaS来讲,不需要进行任何的容量规划。而PaaS提供了扩容能力但是相对缓慢,并且容量评估复杂。
用户部署的FaaS无法维护长连接,因为函数用完就会被销毁,但可以将连接维护在外部服务中以保持长连接。同样的,对于服务的状态,也只能存储在外部资源中来提供有状态的服务。
FaaS可以不需要空闲流量,只在请求时才使用资源(一些云厂商支持预留一部分资源在空闲时使用)。而PaaS一般需要一定的资源来保持空闲容量。
FaaS计费粒度更细,通常以计算时间、调用次数、使用的流量等计费,代码未运行时不产生费用,而PaaS通常以资源和时间粒度计费。以腾讯云的SCF为例:
- 资源使用费用:0.00011108元/GBs
- 调用次数费用:0.0133元/万次
- 外网出流量费用:各地域均有不同定价,中国大陆 0.80 元/GB
- 预置并发闲置费用:0.00005471元/GBs
4. FaaS平台架构
FaaS的简单架构包括以下四种元素:
- 事件源:触发函数实例执行的事件或者流
- 函数实例:单个函数实例,可以通过指令扩缩容
- FaaS控制器:部署、控制、监控函数实例
- 平台服务:必要的集群或者云服务
这四种元素的关系如下:
更具体的可以参考后文中OpenFaaS的架构图。
另外一种角度看,函数开发完成后,会经历构建、部署、扩缩容等不同生命阶段:
二、FaaS供应商
目前主流的云厂商,都有提供FaaS服务,并且会集成各种同步和异步的事件源,负责函数的扩缩容和部署,按照调用计费。
厂商 | FaaS称呼 | 文档入口 | 使用框架 |
---|---|---|---|
Cloud Functions | 链接 | ||
AWS | Lambda | 链接 | |
腾讯云 | SCF / Serverless Cloud Function / 云函数 | 链接 | |
阿里云 | Function Compute / 函数计算 | 链接 |
1. 腾讯云 SCF
本节动图演示使用腾讯云的云函数(文档地址),通过其提供的Web IDE编辑Python函数,快速的创建一个云函数。
如果以下.gif文件不能正常显示,请使用电脑浏览器打开
几点说明:
- 腾讯云的云函数目前每个月有提供免费的额度(访问次数+运行资源+出流量)
- 如果通过HTTP请求访问函数,需要配置API网关触发
- 网关触发区分是否启用集成响应。若启用,需要按照指定格式返回JSON结构,不然会报错。如果不启用,则会直接将变量dump出来。
2. 腾讯云 Serverless
本节动图演示使用腾讯云的Serverless服务(文档地址),在几分钟内,将一个静态网站部署上去并能正常访问。
目前腾讯云的Serverless服务是免费的,对于想搭建自己网站的用户而言,无需购买云服务器,只需要花几块钱购置域名,配置其指向Serverless服务即可拥有自己的网站了。
如果以下.gif文件不能正常显示,请使用电脑浏览器打开
几点说明:
- 静态页面配置实际是将产生的页面存放在腾讯云的对象存储服务(COS)
- Serverless服务创建的桶命名为
my-bucket-XXX
,如果创建多个静态网站可能会有问题,建议删除桶+注销Serverless服务清理后,重试 - 如果需要使用单独的域名,可以根据Serverless页面的提示,将API网关域名地址配置到独立域名的CNAME中。CNAME记录用于将一个域名(同名)映射到另一个域名(真实名称),域名解析服务器遇到CNAME记录会以映射到的目标重新开始查询
- 用到了serverless framework(sls指令)进行部署,操作简单
- 需要注意sls有npm依赖,也可以直接安装二进制文件
3. 常见事件源
- 请求 API 网关的事件
- 定时触发
- 消息队列触发
- COS Bucket 中的对象创建和对象删除事件
4. 应用场景汇总
各大厂商均在云函数的介绍页面,挂了一些应用场景的描述。下边以Google Cloud Functions和AWS Lambda的几个示图做简单的介绍。
- Git push 触发slack消息推送
- 新用户注册触发短信发送
- 实时文件处理,数据库/流触发。函数功能包括审核、压缩、识别等。
- 物联网传感器信息采集
- 无状态请求,比如天气状况,拉取数据库内容
- 用户触发状态变更推送
这些应用场景具有一些特点,也可以说是哪些场景适合使用FaaS:
- 并发相对较低
- 功能独立,函数间交互较少
- 多为无状态的
- 部分请求计算量大的
三、FaaS平台的架构
1. 当前FaaS框架
这里列举了当前较为流行的FaaS框架,以及他们的主页链接、Github地址和Star数。Openfaas是目前Star最多的,而且也更新也是几个项目中较频繁的,像Fn项目很久没有更新,这里就没有列出来。
框架 | 链接 | Star |
---|---|---|
OpenFaaS | 主页 Github | 19.5k |
OpenWhisk | 主页 Github | 5.2k |
Fission | 主页 Github | 6k |
Kubeless | 主页 Github | 6.4k |
Knative | 主页 Github | 3.6k |
2. 部署工具 – Serverless Framework
不是Serverless框架,而是一个部署Serverless应用的工具。
说明文档:https://github.com/serverless/serverless/blob/HEAD/README_CN.md
支持腾讯云SCF、AWS Lambda等部署。
3. OpenFaaS
OpenFaaS 主要是在K8s之上做了一些抽象的封装,每个函数或者服务会构建成镜像,以供编排。使用PLONK栈,分别是:
- Prometheus
- Linux/Linkerd*
- OpenFaaS
- NATS
- Kubernetes
OpenFaaS默认会创建两个命名空间,openfaas
和openfaas-fn
。前者是用于维护OpenFaaS自身组件,后者用于维护创建的函数部署。“faas-netes"子项目,用于部署OpenFaaS到K8s集群。
接下来一节会介绍在MacOS上部署OpenFaaS以及创建、部署函数的过程。
四、OpenFaaS部署实践 [MacOS]
环境:Macbook (macOS 10.15.7)
部署时间:2021-03-21
部署完成后各个组件的版本情况:
- minikube version: v1.18.1
- Docker version: 18.09.2
- kubectl client version: v1.20.5
- faas-cli: version: 0.13.9
1. 安装Docker
因为机器上之前就有安装docker,这次没有重新安装。如果有更新需求,可以参考这里的官方文档。
2. 安装K8s相关组件
安装 minikube
brew install minikube
启动 minikube
➜ ~ minikube start
😄 Darwin 10.15.7 上的 minikube v1.18.1
✨ 根据现有的配置文件使用 docker 驱动程序
👍 Starting control plane node minikube in cluster minikube
🏃 Updating the running docker "minikube" container ...
🐳 正在 Docker 20.10.3 中准备 Kubernetes v1.20.2…
🔎 Verifying Kubernetes components...
▪ Using image kubernetesui/dashboard:v2.1.0
▪ Using image gcr.io/k8s-minikube/storage-provisioner:v4
▪ Using image kubernetesui/metrics-scraper:v1.0.4
🌟 Enabled addons: storage-provisioner, default-storageclass, dashboard
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
安装kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/darwin/amd64/kubectl"
chmod +x ./kubectl
sudo mv ./kubectl /usr/local/bin/kubectl
查看kubectl版本信息
kubectl version
3. 通过 faas-nets 部署 OpenFaaS
git clone https://github.com/openfaas/faas-netes
cd faas-netes
kubectl apply -f namespaces.yml
kubectl apply -f ./yaml/
设置base-auth用户名(admin) 和密码,这个密码后边有用。如果为了简单测试,也可以将其设置为简单易记的短字符串。
export PASSWORD=$(head -c 12 /dev/urandom | shasum| cut -d' ' -f1)
echo $PASSWORD
kubectl -n openfaas create secret generic basic-auth --from-literal=basic-auth-user=admin --from-literal=basic-auth-password=$PASSWORD
4. 拉起并展示minikube的控制面板
启动minikube控制面板、获得访问地址。注意,启动之后不能 Ctrl + C
结束掉,不然HTTP服务就关掉了。
➜ ~ minikube dashboard --url
🤔 正在验证 dashboard 运行情况 ...
🚀 Launching proxy ...
🤔 正在验证 proxy 运行状况 ...
http://127.0.0.1:51502/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/
点击最后的地址即可访问,minikube面板如下(选择了命名空间 openfaas
):
5. 拉起并展示OpenFaaS的控制面板
查询OpenFaaS控制面板地址,这里涉及到minikube获得服务访问地址的方法:
➜ ~ minikube service gateway-external --url -n openfaas
🏃 Starting tunnel for service gateway-external.
|-----------|------------------|-------------|------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|------------------|-------------|------------------------|
| openfaas | gateway-external | | http://127.0.0.1:53156 |
|-----------|------------------|-------------|------------------------|
http://127.0.0.1:53156
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
点开最后的地址即可访问,用户名和密码就是在 3. 通过 faas-nets 部署 OpenFaaS 小节中设置的admin和$PASSWORD
。OpenFaaS面板如下:
页面提示中可以看到,当前没有任何的函数部署。如果要部署新的函数,有两种方式:一种是通过页面进行操作,就是点击页面上的"Deploy New Function"按钮,一种是通过faas-cli进行部署。
6. 通过页面部署函数
点击 按钮,进入选择常用函数页面,也可以选择自定义的函数部署,不过要事先创建好镜像。这里选择常用函数shasum来部署(点选shasum- 点击右下角DEPLOY即可):
调用测试
部署完成之后,在页面左侧会出现一个"shasum"的函数,点击进入函数信息页面。其中包括对应的镜像地址、函数状态、函数URL、函数的进程
7. 通过faas-cli部署函数
7.1 安装faas-cli
brew install faas-cli
Linux上可以通过下边的方式安装:
curl -sSL https://cli.openfaas.com | sh
7.2 查询OpenFaaS提供的模板
faas-cli template store list
7.3 创建函数
根据文档指引,创建一个Python3的简单函数:
mkdir fn && cd fn
faas-cli new pycon --lang python3
得到的主要文件
pycon.yml
pycon/handler.py
pycon/requirements.txt
7.4 构建函数镜像
有很多构建选项,可以参考文档。这里简单的进行构建:
faas-cli build -f pycon.yml
7.5 登入
在之前的3. 通过 faas-nets 部署 OpenFaaS小节中有提到过的密码,同时需要指定网关地址,即#拉起并展示OpenFaaS的控制面板小节中提到的链接。
faas-cli login --password 9013a977f4ded57a72f395f03dff3218df254583 --gateway http://127.0.0.1:53156
其实如果不想记住这个忘关地址,可以每次去动态获取也可以:
faas-cli login --password 9013a977f4ded57a72f395f03dff3218df254583 --gateway $(minikube service gateway-external --url)
7.6 推送镜像(使用Minikube才有的问题)
在OpenFaaS ISSUE #135 中有提到minikube情况有点特殊,不能直接使用docker中存在的镜像。一定需要取从DockerHub或本地的Registry才行。
minikube
is a special case - you will probably have to push to a registry for that - either the Docker Hub or a local registry - see also the Minkube registry add-ons.
不然到话,部署到时候会有如下的错误,提示拉取不到镜像:
Failed to pull image “pycon:latest”: rpc error: code = Unknown desc = Error response from daemon: pull access denied for pycon, repository does not exist or may require ‘docker login’: denied: requested access to the resource is denied
不使用Docker Hub的本地推送方法看上去有些麻烦,所以我直接登录并推送镜像到Docker Hub了。
直接docker push不行:
docker image push pycon:latest
The push refers to repository [docker.io/library/pycon]
…
denied: requested access to the resource is denied
原因是第一行显示的那样,他会认为要将那个镜像直接推送到docker.io/library/pycon
而不是你的个人目录。可以通过打一个tag(简单的认为是对那个镜像加了个软链一样)来指向自己的仓库,然后再进行推送:
docker login
docker tag pycon panzhongxian/pycon
docker image push panzhongxian/pycon:latest
最后将pycon.yml文件做一下修改:
image: pycon:latest
# 修改为⬇️
image: panzhongxian/pycon:latest
7.7 部署函数
同样需要指定网关:
faas-cli deploy -f pycon.yml --gateway http://127.0.0.1:53156
成功后会列出函数的访问地址:
Deploying: pycon.
Deployed. 202 Accepted.
URL: http://127.0.0.1:53156/function/pycon
查看是否成功部署了pod
kubectl get pods -n openfaas-fn
返回我们通过页面部署的一个pod和另外一个通过faas-cli部署的pod
NAME READY STATUS RESTARTS AGE pycon-76f6d9876b-t8zs9 1/1 Running 1 3m shasum-67dddcdb6-6jm9t 1/1 Running 1 175m
7.8 测试函数
curl http://127.0.0.1:53156/function/pycon -X POST --data "test"
7.9 修改函数
修改"pycon/handler.py"文件,最初的文件内容为:
def handle(req):
"""handle a request to the function
Args:
req (str): request body
"""
return req
req
是HTTP POST的内容。可以对其进行计算之后,然后再返回结果。再根据上述过程的部署即可。
8. 清理OpenFaaS部署
当我们测试完之后,需要清理对应的进程、资源。具体步骤如下:
清理账号密码
kubectl delete secret basic-auth -n openfaas
进入目录faas-netes,清理资源文件
kubectl delete -f ./yaml
清理函数命名空间 openfaas-fn
kubectl delete namespace openfaas-fn
清理框架命名空间 openfaas
kubectl delete namespace openfaas
五、附录
K8s的一些常用操作
之前没有利用K8s进行容器编排的经验,这里记录一下在部署过程中的一些技巧。
JSONPath 支持
Kubectl 使用 JSONPath 表达式来过滤 JSON 对象中的特定字段并格式化输出。本节列出一些查询的常用操作,其他详细参数可以参考下边链接:
https://kubernetes.io/zh/docs/reference/kubectl/jsonpath/
显示所有pod中的容器名、镜像名
kubectl get pods --all-namespaces -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.name}{", "}{.image}{", "}{end}{end}'
登录运行中的容器和镜像调试
参考使用容器 exec 进行调试,主要的用法是:
kubectl exec ${POD_NAME} -c ${CONTAINER_NAME} -- ${CMD} ${ARG1} ${ARG2} ... ${ARGN}
也就是上述命令让运行的容器运行指定的指令:
kubectl exec -n openfaas-fn shasum-67dddcdb6-6jm9t -c shasum -- netstat -alnp
如果要通过终端进入到容器的shell,需要加上-t -i
或者长指令--stdin --tty
:
# 以下任意一种方式都可以。
kubectl exec --stdin --tty -n openfaas-fn shasum-67dddcdb6-6jm9t -c shasum -- /bin/sh
kubectl exec -it -n openfaas-fn shasum-67dddcdb6-6jm9t -c shasum -- /bin/sh
TODO
- 压测触发OpenFaaS的自动扩容
- OpenFaaS框架细节