功能即服务(FaaS)是一种无服务器计算方法,包括在无状态,临时容器中运行应用程序的逻辑,这些容器由特定事件触发,这些事件可能只持续一次调用;AWS Lambda 和 Google Cloud Run 是 FaaS 的流行实现。

OpenFaaS是一个无服务器计算框架,在开源社区中获得了很大的关注。它允许您在Docker Swarm或Kubernetes之上轻松构建自己的FaaS无服务器计算平台,同时还为您提供构建功能所需的工具。

faasd通过依赖containerd,可以在不需要容器编排引擎的情况下运行OpenFaaS,这使其成为构建不需要太多计算资源的无服务器家庭实验室的理想选择;非常适合像Raspberry Pi这样的单板计算机。

在这篇博客文章中,我将描述如何通过在单个Raspberry Pi上安装faasd来构建自己的OpenFaaS无服务器平台,以及如何构建并将第一个函数部署到OpenFaas。

安装依赖项

首先,进入您的Raspberry Pi以安装一些依赖项:ssh

sudo apt update \
	&& sudo apt install -qy git runc bridge-utils

安装容器

由于Rapsberry Pi具有架构armv7

pi@raspberrypi:~ $ uname -m
armv7l

我们不能使用容器维护者发布的二进制文件,因为它们只与 .x86_64

因此,为了安装容器,我们可以:

  • 按照此处
    提供的说明在树莓派上构建二进制文件或

  • 使用@alexellisuk在他的Github存储库中提供的预构建的二进制文件

让我们从下载容器二进制文件开始

pi@raspberrypi:~ $ curl -sSL https://github.com/alexellis/containerd-armhf/releases/download/v1.3.2/containerd.tgz | sudo tar -xvz --strip-components=2 -C /usr/local/bin/
./bin/containerd-shim-runc-v1
./bin/containerd-stress
./bin/ctr
./bin/containerd
./bin/containerd-shim-runc-v2
./bin/containerd-shim

获取容器 systemd 单元文件

pi@raspberrypi:~ $ sudo wget --output-document=/etc/systemd/system/containerd.service https://raw.githubusercontent.com/containerd/containerd/v1.3.2/containerd.service--2020-02-09 16:44:04--  https://raw.githubusercontent.com/containerd/containerd/v1.3.2/containerd.service

2020-02-09 16:44:04 (6.45 MB/s) - ‘/etc/systemd/system/containerd.service’ saved [641/641]

启动容器并在系统启动时启用它

pi@raspberrypi:~ $ sudo systemctl enable containerd
Created symlink /etc/systemd/system/multi-user.target.wants/containerd.service → /etc/systemd/system/containerd.service.
pi@raspberrypi:~ $ sudo systemctl start containerd.service
pi@raspberrypi:~ $ systemctl status containerd.service 
● containerd.service - containerd container runtime
   Loaded: loaded (/etc/systemd/system/containerd.service; enabled; vendor preset: enabled)
   Active: active (running) since Sun 2020-02-09 16:45:32 CET; 47s ago
     Docs: https://containerd.io
  Process: 2763 ExecStartPre=/sbin/modprobe overlay (code=exited, status=0/SUCCESS)
 Main PID: 2764 (containerd)
    Tasks: 13
   Memory: 19.2M
   CGroup: /system.slice/containerd.service
           └─2764 /usr/local/bin/containerd

设置容器网络

我们需要启用 Linux 内核桥接模块和 IPv4 转发,如下所示:

pi@raspberrypi:~ $ sudo modprobe br_netfilter
pi@raspberrypi:~ $ sudo sysctl net.bridge.bridge-nf-call-iptables=1
net.bridge.bridge-nf-call-iptables = 1
pi@raspberrypi:~ $ sudo /sbin/sysctl -w net.ipv4.conf.all.forwarding=1

我们还需要使用以下命令安装CNI网络插件:

pi@raspberrypi:~ $ sudo mkdir -p /opt/cni/bin
pi@raspberrypi:~ $ curl -sSL https://github.com/containernetworking/plugins/releases/download/v0.8.5/cni-plugins-linux-arm-v0.8.5.tgz | sudo tar -xz -C /opt/cni/bin
pi@raspberrypi:~ $ ls -l /opt/cni/bin/
total 64436
-rwxr-xr-x 1 root root  3775719 Jan 22 19:52 bandwidth
-rwxr-xr-x 1 root root  4255875 Jan 22 19:52 bridge
-rwxr-xr-x 1 root root 10706922 Jan 22 19:52 dhcp
-rwxr-xr-x 1 root root  5394554 Jan 22 19:52 firewall
-rwxr-xr-x 1 root root  2872015 Jan 22 19:52 flannel
-rwxr-xr-x 1 root root  3843695 Jan 22 19:52 host-device
-rwxr-xr-x 1 root root  3359276 Jan 22 19:52 host-local
-rwxr-xr-x 1 root root  3976434 Jan 22 19:52 ipvlan
-rwxr-xr-x 1 root root  3015277 Jan 22 19:52 loopback
-rwxr-xr-x 1 root root  4046458 Jan 22 19:52 macvlan
-rwxr-xr-x 1 root root  3637166 Jan 22 19:52 portmap
-rwxr-xr-x 1 root root  4187702 Jan 22 19:52 ptp
-rwxr-xr-x 1 root root  3152425 Jan 22 19:52 sbr
-rwxr-xr-x 1 root root  2665626 Jan 22 19:52 static
-rwxr-xr-x 1 root root  3087310 Jan 22 19:52 tuning
-rwxr-xr-x 1 root root  3976306 Jan 22 19:52 vlan

安装 faasd

安装faas-cli

在安装 faasd 之前,让我们安装 faas-cli。 是命令行实用程序,可用于与OpenFaaS交互,并允许我们构建和部署函数。faas-cli

pi@raspberrypi:~ $ curl -sLfS https://cli.openfaas.com | sudo sh
armv7l
Downloading package https://github.com/openfaas/faas-cli/releases/download/0.11.7/faas-cli-armhf as /tmp/faas-cli-armhf
Download complete.

Running with sufficient permissions to attempt to move faas-cli to /usr/local/bin
New version of faas-cli installed to /usr/local/bin
Creating alias 'faas' for 'faas-cli'.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|

CLI:
 commit:  30b7cec9634c708679cf5b4d2884cf597b431401
 version: 0.11.7

您还可以使用以下命令启用 bash-complete:faas-cli

pi@raspberrypi:~ $ source <(faas-cli completion --shell bash)

安装faasd

让我们使用以下命令获取最新的二进制文件faasd

pi@raspberrypi:~ $ sudo wget --output-document=/usr/local/bin/faasd https://github.com/openfaas/faasd/releases/download/0.7.4/faasd-armhf && sudo chmod +x /usr/local/bin/faasd

2020-02-09 17:10:19 (662 KB/s) - ‘/usr/local/bin/faasd’ saved [14548992/14548992]

pi@raspberrypi:~ $ faasd version 
  __                     _ 
 / _| __ _  __ _ ___  __| |
| |_ / _` |/ _` / __|/ _` |
|  _| (_| | (_| \__ \ (_| |
|_|  \__,_|\__,_|___/\__,_|

faasd
Commit: 592f3d3cc073ca6af83fac3013cc2f4743d05e52
Version: 0.7.4

现在我们只需要运行 faasd 安装:

pi@raspberrypi:~ $ export GOPATH=$HOME/go/
pi@raspberrypi:~ $ mkdir -p $GOPATH/src/github.com/openfaas
pi@raspberrypi:~ $ cd $GOPATH/src/github.com/openfaas 
pi@raspberrypi:~/go/src/github.com/openfaas $ git clone https://github.com/openfaas/faasd.git
pi@raspberrypi:~/go/src/github.com/openfaas $ cd faasd/
pi@raspberrypi:~/go/src/github.com/openfaas/faasd $ sudo faasd install 
Login with:
  sudo cat /var/lib/faasd/secrets/basic-auth-password | faas-cli login -s

最后,如命令输出中提到的,登录使用能够与您的新OpenFaaS安装进行交互:faas-cli

pi@raspberrypi:~ $ sudo cat /var/lib/faasd/secrets/basic-auth-password | faas-cli login -s
Calling the OpenFaaS server to validate the credentials...
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.
credentials saved for admin http://127.0.0.1:8080

访问 OpenFaaS 界面

一旦设置并运行,就可以在浏览器上访问 OpenFaaS 用户界面。由于它受基本身份验证的保护,因此您需要使用 和 下可用的用户名和密码登录。faasdhttp://RASPBERRYPI_IP:8080/var/lib/faasd/secrets/basic-auth-password/var/lib/faasd/secrets/basic-auth-user

登录后,您将看到以下界面:

OpenFaaS Web 界面

OpenFaas商店中已经提供了一些功能,您可以直接从Web用户界面轻松部署这些功能。让我们尝试部署该函数:figlet

部署无花果函数

一旦函数的状态为 ,让我们尝试调用它:Ready

使用 faas-cli

现在让我们使用与 OpenFaas 网关进行交互。首先,我们需要使用工作站中的命令登录到 OpenFaas 网关。
从 Raspberry Pi 上的文件中获取密码,并将其存储在工作站上的文件中,因为这是登录所必需的。在这里,我将密码存储在文件中:faas-clifaas login/var/lib/faasd/secrets/basic-auth-password~/.faas_pass

$ cat ~/.faas_pass | faas login -s --gateway http://raspberrypi.loc:8080  
Calling the OpenFaaS server to validate the credentials...
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.
credentials saved for admin http://raspberrypi.loc:8080

我们可以使用以下命令列出并检查已部署的函数:

$ faas list --gateway http://raspberrypi.loc:8080
Function                      	Invocations    	Replicas
figlet                        	1              	1    

$ faas describe --gateway http://raspberrypi.loc:8080 figlet
Name:                figlet
Status:              Ready
Replicas:            1
Available replicas:  1
Invocations:         1
Image:               
Function process:    
URL:                 http://raspberrypi.loc:8080/function/figlet
Async URL:           http://raspberrypi.loc:8080/async-function/figlet

用于从应用商店部署函数faas-cli

我们可以使用以下命令列出平台的 OpenFaas 存储中的可用函数:armhf

$ faas store list --platform armhf

FUNCTION                    DESCRIPTION
NodeInfo                    Get info about the machine that you...
Figlet                      Generate ASCII logos with the figlet CLI
SSL/TLS cert info           Returns SSL/TLS certificate informati...
YouTube Video Downloader    Download YouTube videos as a function
OpenFaaS Text-to-Speech     Generate an MP3 of text using Google'...
nslookup                    Uses nslookup to return any IP addres...
Docker Image Manifest Query Query an image on the Docker Hub for ...
Left-Pad                    left-pad on OpenFaaS
Identicon Generator         Create an identicon from a provided s...

让我们使用以下命令部署函数:nslookupfaas store deploy

$ faas store deploy --platform armhf --gateway http://raspberrypi.loc:8080 nslookup
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.

Deployed. 200 OK.
URL: http://raspberrypi.loc:8080/function/nslookup

$ faas describe nslookup --gateway http://raspberrypi.loc:8080
Name:                nslookup
Status:              Ready
Replicas:            1
Available replicas:  1
Invocations:         0
Image:               
Function process:    
URL:                 http://raspberrypi.loc:8080/function/nslookup
Async URL:           http://raspberrypi.loc:8080/async-function/nslookup

让我们从命令行调用我们的新函数:

$ echo "openfaas.com" | faas invoke nslookup --gateway http://raspberrypi.loc:8080 
nslookup: can't resolve '(null)': Name does not resolve

Name:      openfaas.com
Address 1: 185.199.108.153
Address 2: 185.199.111.153
Address 3: 185.199.109.153
Address 4: 185.199.110.153

瞧!我们已经从命令行部署并测试了我们的第一个函数。????

构建自己的函数

如果我们想构建一个新的函数,并将其部署到Raspberry PI上的OpenFaas,该怎么办?
提供了一种实现此目的的便捷方法,因为它为多种编程语言和命令提供了模板,使我们能够构建新功能并将其部署到OpenFaas。
但是,由于我们没有在Rapsberry Pi上安装Docker,因此我们需要使用另一个工具构建我们的函数:buildkit。faas-cli

下载构建工具包二进制文件

由于 二进制文件已经在项目的 Github 存储库中可用,因此我们不需要自己编译它们。让我们获取 RPi 上的最新二进制文件:buildkitarmv7buildkit

pi@raspberrypi:~ $ wget -qO- https://github.com/moby/buildkit/releases/download/v0.6.4/buildkit-v0.6.4.linux-arm-v7.tar.gz | sudo tar -xz -C /usr/local/bin/ --strip-components=1 
pi@raspberrypi:~ $ /usr/local/bin/buildkitd --version 
buildkitd github.com/moby/buildkit v0.6.4 ebcef1f69af0bbca077efa9a960a481e579a0e89
pi@raspberrypi:~ $ /usr/local/bin/buildctl --version 
buildctl github.com/moby/buildkit v0.6.4 ebcef1f69af0bbca077efa9a960a481e579a0e89

构建新函数

我们将在其中构建一个小函数并将其部署到OpenFaas。
幸运的是,我们不必从头开始做所有事情。我们可以使用OpenFaas模板存储中已经可用的模板之一。
我们可以使用以下命令列出可用于平台的模板:golangarmhf

pi@raspberrypi:~ $ faas template store list --platform armhf 

NAME                    SOURCE             DESCRIPTION
dockerfile-armhf        openfaas           Classic Dockerfile armhf template
go-armhf                openfaas           Classic Golang armhf template
node-armhf              openfaas           Classic NodeJS 8 armhf template
python-armhf            openfaas           Classic Python 2.7 armhf template
python3-armhf           openfaas           Classic Python 3.6 armhf template
node10-express-armhf    openfaas-incubator Node.js 10 powered by express armhf template
python3-flask-armhf     openfaas-incubator Python 3.6 Flask armhf template
python3-http-armhf      openfaas-incubator Python 3.6 with Flask and HTTP for ARMHF
node8-express-armhf     openfaas-incubator Node.js 8 powered by express armhf template
golang-http-armhf       openfaas-incubator Golang HTTP armhf template
golang-middleware-armhf openfaas-incubator Golang Middleware armhf template

我们将在这里使用经典的golang模板,所以让我们创建一个新函数:

pi@raspberrypi:~ $ mkdir ~/openfaas && cd ~/openfaas
pi@raspberrypi:~/openfaas $ faas new hello-go --lang go-armhf --prefix myedes
Folder: hello-go created.
  ___                   _____           ____
 / _ \ _ __   ___ _ __ |  ___|_ _  __ _/ ___|
| | | | '_ \ / _ \ '_ \| |_ / _` |/ _` \___ \
| |_| | |_) |  __/ | | |  _| (_| | (_| |___) |
 \___/| .__/ \___|_| |_|_|  \__,_|\__,_|____/
      |_|


Function created in folder: hello-go
Stack file written: hello-go.yml

Notes:
You have created a new function which uses Golang 1.11
To include third-party dependencies, use a vendoring tool like dep:
dep documentation: https://github.com/golang/dep#installation

You may also like the golang-middleware and golang-http templates
available via "faas-cli template store"

该选项允许您指定用于推送和拉取函数映像的自定义 docker 注册表。--prefix

我们使用的模板由一个简单的go函数组成,该函数返回文本消息以及请求正文。逻辑可以在文件中找到:hello-go/handler.go

pi@raspberrypi:~/openfaas $ cat hello-go/handler.go 
package function

import (
	"fmt"
)

// Handle a serverless request
func Handle(req []byte) string {
	return fmt.Sprintf("Hello, Go. You said: %s", string(req))
}

使用该选项,我们可以为函数生成生成上下文,而无需实际生成函数的映像。当我们想要使用不同的工具来构建我们的映像时,这很有用,在我们的例子中:--shrinkwrapbuildkit

pi@raspberrypi:~/openfaas $ faas build -f hello-go.yml --shrinkwrap 
[0] > Building hello-go.
Clearing temporary build folder: ./build/hello-go/
Preparing: ./hello-go/ build/hello-go/function
Building: docker.io/myedes/hello-go:latest with go-armhf template. Please wait..
hello-go shrink-wrapped to ./build/hello-go/
[0] < Building hello-go done in 0.01s.
[0] Worker done.

Total build time: 0.01s

如我们所见,该命令在文件夹内生成了一些文件;我们的构建环境:build/

build/
└── hello-go
    ├── Dockerfile
    ├── function
    │   └── handler.go
    ├── go.mod
    ├── main.go
    └── template.yml

2 directories, 5 files

在构建映像之前,我们需要配置身份验证,以便能够推送到 docker 注册表。但是,由于我们没有安装 Docker,因此我们无法使用该命令,因此我们必须手动创建该文件。
对于 Docker Hub ,我们需要从用户界面生成一个令牌,然后在 RPi 上创建,如下所示:docker login~/.docker/config.json~/.docker/config.json

pi@raspberrypi:~/openfaas $ export DOCKERHUB_USERNAME=myedes
pi@raspberrypi:~/openfaas $ export DOCKERHUB_TOKEN=<PERSONAL ACCESS TOKEN>
pi@raspberrypi:~/openfaas $ export DOCKER_AUTH=$(echo -n "$DOCKERHUB_USERNAME:$DOCKERHUB_TOKEN" | base64)

pi@raspberrypi:~/openfaas $ cat > ~/.docker/config.json << EOF 
{
    "auths": {
        "https://index.docker.io/v1/": {
            "auth": "$DOCKER_AUTH"
 		}
 	}
}
EOF

让我们在后台启动守护程序,然后开始构建:buildkitd

# Run the buildkitd daemon
pi@raspberrypi:~/openfaas $ sudo /usr/local/bin/buildkitd & 
[1] 15587

# Build and push the function image to hub.docker.com
pi@raspberrypi:~/openfaas $ sudo buildctl build \
	--frontend dockerfile.v0 \
    --local context=build/hello-go/ \
    --local dockerfile=build/hello-go/ \
    --output type=image,name=docker.io/myedes/hello-go:latest,push=true

[+] Building 81.3s (26/26) FINISHED
...
 => => pushing layers
 => => pushing manifest for docker.io/myedes/hello-go:latest
有关如何使用的更多信息,请务必查看 moby/buildkit Github 存储库。buildkit

部署函数

由于我们已经构建了函数的映像并将其推送到注册表,因此我们现在可以继续将新功能部署到OpenFaas网关:

pi@raspberrypi:~/openfaas $ faas deploy -f hello-go.yml 
Deploying: hello-go.
WARNING! Communication is not secure, please consider using HTTPS. Letsencrypt.org offers free SSL/TLS certificates.

Deployed. 200 OK.
URL: http://127.0.0.1:8080/function/hello-go

通过检查我们的新函数,我们可以看到它处于"就绪"状态:

pi@raspberrypi:~/openfaas $ faas describe hello-go 
Name:                hello-go
Status:              Ready
Replicas:            1
Available replicas:  1
Invocations:         0
Image:               
Function process:    
URL:                 http://127.0.0.1:8080/function/hello-go
Async URL:           http://127.0.0.1:8080/async-function/hello-go

现在,我们可以使用 Raspberry Pi 中的命令调用它:faas invoke

pi@raspberrypi:~/openfaas $ echo "Hello OpenFaas" | faas invoke hello-go 
Hello, Go. You said: Hello OpenFaas

或从我们的工作站,但我们需要使用以下参数指定网关:--gateway

$ echo "Hello from laptop" | faas invoke --gateway http://raspberrypi.loc:8080 hello-go

Hello, Go. You said: Hello from laptop

就是这样,我们已经构建并部署了我们的第一个函数到OpenFaas上运行在单个Raspberry PI ????上非常酷,不是吗?

结论

在这篇博文中,我们介绍了如何在Raspberry Pi板上运行基于OpenFaas的FaaS无服务器平台,以及如何构建和部署一个简单的函数。
尽管与OpenFaas相比,faasd的功能仍然受到一些限制,但它对于像家庭实验室这样的小型设置非常有用,特别是不需要维护Kubernetes或Docker Swarm集群。

最后,向@alexellisuk和OpenFaas团队致敬,感谢这个令人敬畏的项目!

引用:

  • https://blog.alexellis.io/faasd-for-lightweight-serverless/

  • https://docs.openfaas.com/

  • https://blog.alexellis.io/quickstart-openfaas-cli/

  • https://github.com/openfaas/faasd

  • https://github.com/moby/buildkit