文章目录
原理
技术简介
OpenFaaS是golang编写的一个使用Docker和Kubernetes构建的serveless框架
和Fnproject 有点像,只是 Openfaas 并不是直接抓取容器的标准输出,而是写一个 Function Watchdog 作为容器的启动进程,暴露 http 服务,用于和调度系统交互,然后直接调用进程运行 Function 获取输出。
Prometheus:监控系统报警框架
watchdog:https://news.ycombinator.com/item?id=15116834
Swarm:提供 Docker 容器集群服务
架构
当Gateway作为一个入口,当CLI或者web页面发来要部署或者调用一个函数的时候,Gateway会将请求转发给Provider,同时会将监控指标发给Prometheus。AlterManager会根据需求,调用API自动伸缩函数。
结构分析
- 基本的安全验证
- 和函数相关的代理转发
- 同步函数
- 列出函数
- 部署函数
- 删除函数
- 更新函数
- 同步函数
- 异步函数
- Prometheus的监控
- ui
- 自动伸缩
- 根据每秒请求数来做伸缩
- 最小/最大副本数 通过向函数添加标签, 可以在部署时设置最小 (初始) 和最大副本数。
- 通过内存和CPU的使用量。
性能
社区活跃度
Dec 18, 2016 – Dec 27, 2018
https://kenfdev.o6s.io/github-stats-page#/
1.社区活动
开发工作量平均每周大约5个commits
2.社区规模
github核心开发人员3名
3.社区表现
issues的平均close周期比较长
5.社区多样性
Pony factor:1
性能表现
环境
非生产环境
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 2
On-line CPU(s) list: 0,1
Thread(s) per core: 1
Core(s) per socket: 1
Socket(s): 2
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 42
Model name: Intel Xeon E312xx (Sandy Bridge)
Stepping: 1
CPU MHz: 1999.999
BogoMIPS: 3999.99
Hypervisor vendor: KVM
Virtualization type: full
L1d cache: 32K
L1i cache: 32K
L2 cache: 4096K
NUMA node0 CPU(s): 0,1
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
对象
http://192.168.44.204:8080/function/figlet 0.016
http://192.168.44.204:8080/function/nodeinfo 0.2
http://192.168.44.204:8080/function/echoit 0.02
数据
单任务
#!/bin/bash
rm -rf ab.log
for i in $(cat url.txt)
do
if [ "$1" == "" ]
then
echo "is empty"
elif [[ "$2" == "" ]]
then
if [ "$3" == "" ]
then
Echo "c = $1,no t,no n"
ab -c $1 $i >> ab.log &
continue
else
Echo "c = $1,no t,n = $3 "
ab -t $2 -n $3 $i >> ab.log &
continue
fi
elif [[ "$3" == "" ]]
then
Echo "c = $1,t = $2 ,no n"
ab -c $1 -t $2 $i >> ab.log &
continue
else
Echo "c = $1,t = $2 ,n = $3 "
ab -c $1 -t $2 -n $3 $i >> ab.log &
continue
fi
done
多函数
Figlet/nodeino/echoit
http://192.168.44.204:8080/function/figlet
http://192.168.44.204:8080/function/nodeinfo
做压力测试是为了知道服务器(单台)的QPS承受能力是多少。得到我们服务器能承受的最大并发数和最大QPS值,就要进行压力测试
生态圈
内部服务
- 事件源 http,cli等
- CLI: fass_cli
- Prometheus
- watchdog
- Docker/k8s
- NATS Streaming
外部服务
- Openfaas云:使用git管理的多用户无服务器功能
- 触发:kafka\sns\Cloud event\IFTT\Redis\RebbitMQ
生产工具 - faas-netes
高级用法
YAML
provider:
name: faas
gateway: http://127.0.0.1:31112
functions:
first:
lang: python3
handler: ./IamSequin/first
image: sequinyf/first:latest
second:
lang: python3
handler: ./second
image: sequinyf/second:latest
网关URL可以硬编码到YAML文件中,也可以在部署时使用–gateway标志或OPENFAAS_URL env-var覆盖。
函数handler字段指的是可以找到函数源代码的文件夹,它必须是文件夹而不是文件名。
build时需要添加模块
build_options :
- name : dev
packages : #必需包的列表
- make
- automake
- gcc
# - etc.
- name : debug
packages :
- mg
- iw
# - etc.
environment字段
- Content-Type
- 超时
- 日志
也可以在yaml中自定义字段,通过获取环境在函数中获取。
命名空间
//可以通过openfaas cloud实现
工作流
函数调用
从另一个函数调用一个函数的最简单方法是通过OpenFaaS API网关通过HTTP进行调用。此调用不需要知道外部域名或IP地址,它可以gateway通过DNS条目简单地引用API网关。
使用requests库发出http请求
多级页面
html:
http://10.202.26.244:31112/function/sequin-test3/new
http://10.202.26.244:31112/function/sequin-test3/list
权限
API网关
内置基本身份验证
OpenFaaS的API网关提供内置的基本身份验证:
开启basic_auth
# /home/wangyifei03/faas-netes/yaml/gateway-dep.yml
- name: basic_auth
value: "true"
推荐使用helm chart安装的openfaas。在init 参数上开启
--set basic_auth=true
然后创建两个名为 basic-auth-user 和 basic-auth-password的secrets
#sequin
#1a2b3c4d
kubectl create secret generic basic-auth-password --from-file=basic-auth-password=passwd --namespace openfaas-fn
kubectl create secret generic basic-auth-user --from-file=basic-auth-user=user --namespace openfaas-fn
kubectl get secrets
NAME TYPE DATA AGE
basic-auth-password Opaque 1 13m
basic-auth-user Opaque 1 13m
生效后使用faas-cli之前就需要登陆
faas-cli login
其他
反向代理项目(如Kong)来启用OAuth或类似策略
secret
secret用于在函数中使用API令牌,密码等
创建一个secret文件里面存放密码
echo -n '1a2b3c4d' > ./password.txt
创建secret对象
kubectl create secret generic secret-api-key \
--from-file=secret-api-key=password.txt \
--namespace openfaas-fn
kubectl get secrets -n openfaas-fn
NAME TYPE DATA AGE
secret-api-key Opaque 1 4h5m
当部署一个function的时候,编写一个函数去使用它:
package function
import (
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
func getAPISecret(secretName string) (secretBytes []byte, err error) {
secretBytes, err = ioutil.ReadFile("/var/openfaas/secrets/" + secretName)
if err != nil {
secretBytes, err = ioutil.ReadFile("/run/secrets/" + secretName)
}
return secretBytes, err
}
func handle(body []byte) {
key := os.Getenv("Http_X_Api_Key")
secretBytes, err := getAPISecret("secret_api_key")
if err != nil {
log.Fatal(err)
}
secret := strings.TrimSpace(string(secretBytes))
if key == secret {
fmt.Println("Unlocked the function!")
} else {
fmt.Println("Access denied!")
}
}
func Handle(req []byte) string {
handle(req)
return "ok"
}
部署函数,要在函数的yaml文件中指明secret
provider:
name: faas
gateway: http://127.0.0.1:31112
functions:
sec:
lang: go
handler: ./sec
image: sequinyf/sec:latest
secrets:
- secret-api-key
触发的时候,需要添加一个参数
echo | faas-cli invoke temp -H "X-Api-Key=1a2b3c4d"
good
echo | faas-cli invoke temp -H "X-Api-Key=aaaaaa"
no
可以对多个函数设置一个secret或者多个secret
函数
HMAC使用对称密钥,发送方/接收方都提前共享。当想要传输消息时,发送方将生成散列 - 此数据与有效负载一起发送。然后,接收方将使用共享密钥对有效负载进行签名,如果散列匹配,则假定有效负载来自发送方。(有些相应外部系统的功能不支持身份验证,比如webhook)
首先部署env
faas-cli deploy --name env --fprocess="env" --image="functions/alpine:latest"
当使用 --sign 标志时,会生成Http_Hmac字段
echo -n "The message" | faas-cli invoke env --sign=HMAC --key=cookie
Http_Hmac=sha1=9239edfe20185eafd7a5513c303b03d207d22f64
OpenFaaS将HMAC视为环境变量Http_Hmac。生成的值是使用密钥The message --sign后的哈希值cookie,然后使用散列方法sha1。
为HMAC创建一个secret,修改目标Function的yaml指明secret.
官方的目标函数代码:
import os, hmac, hashlib
def validateHMAC(message, secret, hash):
# GitHub and the sign flag prefix the hash with "sha1="
receivedHash = getHash(hash)
# Hash message with secret
#收到请求后,该函数将使用secret对请求消息进行签名。这将创建第二个HMAC,将其与'Http-Hmac`进行比较。
expectedMAC = hmac.new(secret.encode(), message.encode(), hashlib.sha1)
createdHash = expectedMAC.hexdigest()
return receivedHash == createdHash
def getHash(hash):
if "sha1=" in hash:
hash=hash[5:]
return hash
def handle(req):
# We receive the hashed message in form of a header
messageMAC = os.getenv("Http_Hmac")
# Read secret from inside the container
with open("/var/openfaas/secrets/payload-secret","r") as secretContent:
payloadSecret = secretContent.read()
# Function to validate the HMAC
if validateHMAC(req, payloadSecret, messageMAC):
return "Successfully validated: " + req
return "HMAC validation failed."
调用
echo -n "This is a message" | faas-cli invoke hmac-protected --sign hmac --key=<your-secret>
Successfully validated: This is a message
HMAC validation failed.
Openfaas Cloud
原理
主要流程:
- 用户推送代码 - GitHub / GitLab推送事件被发送到github-event / gitlab-event函数,触发CI / CD工作流程
- 用户从一个或多个repos中删除GitHub / GitLab应用程序 - 调用垃圾收集删除1个多功能
- 用户通过路由器使用“漂亮的URL”格式访问功能,并通过API网关将请求路由到功能
特点
- 便携式 - 自托管
- 多用户 - 使用您的GitHub / GitLab身份登录您的个人仪表板
- 自动化由git push(也称为GitOps)触发的CI / CD
- 通过在GitLab中添加GitHub应用程序或存储库标记,只需单击即可在板上添加新的git 存储库
- 立即反馈您的个人仪表板和GitHub支票或GitLab状态
- 使用HTTPS的每个用户或组织的子域
- 使用Docker的buildkit构建快速的非root映像
实践
安装使用说明
环境
Debian9
安装docker
卸载docker
sudo apt-get remove docker \
docker-engine \
docker.io
配置环境
$ sudo apt-get update
$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
gnupg2 \
lsb-release \
software-properties-common
添加软件源的gpg密钥
curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/debian/gpg | sudo apt-key add -
添加docer-ce软件源
sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/debian \
$(lsb_release -cs) \
stable"
apt-get update && apt-get install -y docker-ce=$(apt-cache madison docker-ce | grep 18.09.1 | head -1 | awk '{print $3}’)
锁定版本
apt-mark hold docker-ce
安装k8s
!!!
首先关闭分区
sudo swapoff -a
能翻墙
安装依赖工具、添加 GPG 秘钥、添加软件仓库,进行软件下载 这一步照着k8s的官网来。
apt-get update && apt-get install -y apt-transport-https curl
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
cat <<EOF >/etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
EOF
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl
在官网选一个组网,我用的fannal
kubeadm init --apiserver-advertise-address=你的ip --pod-network-cidr=10.244.0.0/16
不能翻墙
不能翻墙的话需要备好所需的镜像。
# 添加可信密钥
curl -s http://mirrors.aliyun.com/kubernetes/apt/doc/apt-key.gpg | apt-key add -
#添加源地址
cat <<EOF > /etc/apt/sources.list.d/kubernetes.list
deb http://mirrors.aliyun.com/kubernetes/apt kubernetes-xenial main
EOF
#更新
apt-get update
#安装
apt-get install -y kubelet kubeadm kubectl
然后把你准备好的镜像pull下来。
修改/etc/systemd/system/kubelet.service.d/10-kubeadm.conf,这一步是使cgroupdrive支持kubelet 、绕过墙。
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrapkubelet.
conf --kubeconfig=/etc/kubernetes/kubelet.conf --runtimecgroups=/
systemd/system.slice --kubelet-cgroups=/systemd/system.slice --pod-infra-containerimage=
dockerhub.nie.netease.com/whale/pause:3.1"
然后重启服务
systemctl daemon-reload
组网,这个是calico,按照官网的选就行。
kubeadm init --podnetwork-cidr=192.168.0.0/16
网络这里经常会出现问题,看缘分吧,不行就换插件。很容易出现node notfound的问题,具体看解决方法查看https://g.126.fm/028py8g。
openfaas
安装
安装方式:k8s
1 安装cli
curl -sL https://cli.openfaas.com | sudo sh
2 安装
- helm (官网说helm用于生产,yaml适用于开发,这里我用的yaml)
- yaml
git clone https://github.com/openfaas/faas-netes
kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/namespaces.yml
cd faas-netes && kubectl apply -f ./yaml
查看安装情况
kubectl get pod --all-namespaces
使用
Openness 自带的商店可以一键部署一些demo
通过命令行部署
faas-cli store list
faas-cli deploy -f https://raw.githubusercontent.com/openfaas/faas/master/stack.yml
或者openfaas UI http://127.0.0.1:8080
UI
http://localhost:8080
UI 可以查看function的运行情况和状态,也可以通过UI调用函数。
部署function也可以通过UI部署,选择打包好的镜像
监控部分
OpenFaaS使用Prometheus自动跟踪功能指标
部署grafana
现在docker 上找到pull openfaas grafana
https://hub.docker.com/r/stefanprodan/faas-grafana/
kubectl -n openfaas run \
--image=stefanprodan/faas-grafana:4.6.3 \
--port=3000 \
grafana
kubectl -n openfaas expose deployment grafana \
--type=NodePort \
--name=grafana
$GRAFANA_PORT=$(kubectl -n openfaas get svc grafana -o jsonpath="{.spec.ports[0].nodePort}")
prometheus: http://10.202.26.244:31119/graph
Grafana: http://10.202.26.244:30020/dashboard/db/openfaas?refresh=5s&orgId=1
开发流程
Openfaas 支持多种模版
$ faas-cli new --list
Languages available as templates:
- csharp
- dockerfile
- go
- go-armhf
- node
- node-arm64
- node-armhf
- python
- python-armhf
- python3
- ruby
用打包好的模版
faas-cli new --lang python3 hello-openfaas --prefix="<your-docker-username-here>”
该–prefix参数将使用前缀更新image: hello-openfaas.yml,该前缀应该是Docker Hub帐户。
./hello-openfaas.yml
./hello-openfaas
./hello-openfaas/handler.py
./hello-openfaas/requirements.txt
一个待部署的function包含以上几个模块
Yaml文件可以方便的设置function部署环境,包括将多个function组合、超时设置、日志设置等
有使用pip要安装的第三方依赖模块,例如requests或urllib 需要在requirements.txt中声明。
部署时需要首先登陆docker,生成的镜像需要docker用户名做前缀。
部署
faas-cli up -f hello-openfaas.yml
定时样例
OpenFaaS借助k8s的cron job实现定时任务
定时任务执行的函数是nodeinfo函数,我已经部署好了,该函数用于返回服务器信息。
首先创建一个cronjob的yaml文件
# node-cron.yaml
apiVersion: batch/v1beta1
kind: CronJob
metadata:
name: nodeinfo
namespace: openfaas
spec:
schedule: "*/1 * * * *"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 1
failedJobsHistoryLimit: 3
jobTemplate:
spec:
template:
spec:
containers:
- name: faas-cli
image: openfaas/faas-cli:0.7.1
args:
- /bin/sh
- -c
- echo "verbose" | faas-cli invoke nodeinfo -g http://10.202.26.244:31112
restartPolicy: OnFailure
部署:kubectl apply -f node-cron.yaml
查看:
kubectl get cronjob nodeinfo --watch -n openfaas
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
nodeinfo */1 * * * * False 0 38s 12m
nodeinfo */1 * * * * False 1 2s 13m
nodeinfo */1 * * * * False 0 12s 13m
总结
特点
- package in Docker/OCI image format
- Runs on Kubernetes and Docker Swarm native
- CLI available with YAML format for templating and defining functions
- Auto-scal
思考
使用OpenFaas,任何进程或容器都可以打包为Linux或Windows的无服务器功能。对于企业而言,OpenFaaS使用的体系结构提供了无缝插入计划群集和现有微服务的CI/CD工作流的能力,因为OpenFaaS是围绕Docker构建的,所有功能都打包到Docker镜像中。OpenFaaS还为企业提供了一种通过外部API,网关管理和执行函数的无缝方式,并管理函数的生命周期,包括通过提供商进行部署,扩展和secret管理。