Serverless OpenFaas

文章目录

      • 原理
        • 技术简介
        • 架构
        • 结构分析
      • 性能
        • 性能表现
          • 环境
          • 对象
          • 数据
        • 生态圈
      • 高级用法
        • YAML
        • 命名空间
        • 工作流
          • 函数调用
          • 多级页面
        • 权限
          • API网关
            • 内置基本身份验证
            • 其他
          • secret
          • 函数
        • Openfaas Cloud
          • 原理
          • 特点
      • 实践
        • 安装使用说明
          • 环境
            • 安装docker
            • 安装k8s
          • openfaas
            • 安装
            • 使用
        • 定时样例
      • 总结
        • 特点
        • 思考

原理

技术简介

OpenFaaS是golang编写的一个使用Docker和Kubernetes构建的serveless框架
和Fnproject 有点像,只是 Openfaas 并不是直接抓取容器的标准输出,而是写一个 Function Watchdog 作为容器的启动进程,暴露 http 服务,用于和调度系统交互,然后直接调用进程运行 Function 获取输出。

Serverless OpenFaas_第1张图片

Prometheus:监控系统报警框架
watchdog:https://news.ycombinator.com/item?id=15116834
Swarm:提供 Docker 容器集群服务

架构

Serverless OpenFaas_第2张图片
当Gateway作为一个入口,当CLI或者web页面发来要部署或者调用一个函数的时候,Gateway会将请求转发给Provider,同时会将监控指标发给Prometheus。AlterManager会根据需求,调用API自动伸缩函数。

结构分析

  • 基本的安全验证
  • 和函数相关的代理转发
    • 同步函数
      • 列出函数
      • 部署函数
      • 删除函数
      • 更新函数
  • 异步函数
  • Prometheus的监控
  • ui
  • 自动伸缩
    • 根据每秒请求数来做伸缩
    • 最小/最大副本数 通过向函数添加标签, 可以在部署时设置最小 (初始) 和最大副本数。
    • 通过内存和CPU的使用量。

性能

社区活跃度
Dec 18, 2016 – Dec 27, 2018

https://kenfdev.o6s.io/github-stats-page#/
Serverless OpenFaas_第3张图片
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

Serverless OpenFaas_第4张图片
多函数
Figlet/nodeino/echoit
http://192.168.44.204:8080/function/figlet
http://192.168.44.204:8080/function/nodeinfo

Serverless OpenFaas_第5张图片

做压力测试是为了知道服务器(单台)的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

Serverless OpenFaas_第6张图片

其他

反向代理项目(如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=
 Successfully validated: This is a message
 HMAC validation failed.

Openfaas Cloud

原理

Serverless OpenFaas_第7张图片
主要流程:

  • 用户推送代码 - GitHub / GitLab推送事件被发送到github-event / gitlab-event函数,触发CI / CD工作流程
  • 用户从一个或多个repos中删除GitHub / GitLab应用程序 - 调用垃圾收集删除1个多功能
  • 用户通过路由器使用“漂亮的URL”格式访问功能,并通过API网关将请求路由到功能
特点

Serverless OpenFaas_第8张图片

  • 便携式 - 自托管
  • 多用户 - 使用您的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 </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 < /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 安装

  1. helm (官网说helm用于生产,yaml适用于开发,这里我用的yaml)
  2. 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

Serverless OpenFaas_第9张图片

使用

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
Serverless OpenFaas_第10张图片
UI

http://localhost:8080
UI 可以查看function的运行情况和状态,也可以通过UI调用函数。
Serverless OpenFaas_第11张图片

部署function也可以通过UI部署,选择打包好的镜像
Serverless OpenFaas_第12张图片

监控部分

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
Serverless OpenFaas_第13张图片
Grafana: http://10.202.26.244:30020/dashboard/db/openfaas?refresh=5s&orgId=1
Serverless OpenFaas_第14张图片
开发流程

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="

该–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

Serverless OpenFaas_第15张图片

定时样例

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管理。

你可能感兴趣的:(tool)