OpenFaaS 的无状态微服务介绍

阅读数:3 2019 年 12 月 31 日 10:16

OpenFaaS的无状态微服务介绍

本文作者 Alex 将带我们了解了 OpenFaaS 的最新改进,也就是对无状态微服务的完整支持,并给出了一个用 Ruby 和 Sinatra 编写的留言簿示例。

目前,我们已经在 OpenFaaS 0.9.0 中合并并发布了对无状态微服务的支持。这意味着工程师现在可以利用 OpenFaaS 中简单而强大的开发人员体验,打造出管理你所有 FaaS 函数和微服务的单一平台。整套体验的内容从 CLI 到 Prometheus 度量,再到内置的自动扩展都包括在内。甚至缩放到零都得到了支持。本文中,我将引领大家部署一个用 Ruby 和 Sinatra 编写的留言簿示例,这个留言簿由 MySQL 支持,使用 Kubernetes 部署到 OpenFaaS 上。

为什么要这样做?

现代的云原生微服务和 FaaS 函数之间有很多重叠部分,我将在下一部分中具体说明。OpenFaaS 一直支持在 Windows 上运行任何容器或进程,无论是 FaaS 函数、AWS CLI、ImageMagick 甚至是 PowerShell 都可以。社区在短时间内提出了两个要求,这两个要求成为了我们的故事进一步发展的催化剂。

我们在 Wireline.io 的一位新用户提出了一项功能请求,希望增强函数的HTTP 路由功能。Wireline 希望编写出无需任何额外更改,就可以同时运行在 AWS Lambda 和 OpenFaaS 上的函数。大约在同一时间,GitLab 的首席执行官 Sid Sijbrandi 联系了我们,希望了解更多关于无服务器的信息,并想知道如何在 GitLab 上利用它。Sid 问我,OpenFaaS 能否同时用来管理 FaaS 函数,和他的团队更熟悉的一些微服务(例如 Sinatra 应用)。他对在空闲时缩放到零的能力表现出了特别的兴趣。

在开始研究示例,展示如何将 Sid 的请求付诸实践之前,我们先来看一些背景知识。

什么是函数?

在了解什么是“无状态微服务”之前,我们先来看 "FaaS 函数 " 的定义。我在 2017 年 1 月发表的博客文章:函数即服务(FaaS)中给出了具体定义。

函数往往会:

  • 调用短期函数(Lambda 有默认的 1 秒超时设置)
  • 不发布 TCP 服务——经常访问第三方服务或资源
  • 往往是临时的 / 事件驱动的,例如响应 Webhooks
  • 应该平稳地应对流量高峰
  • 不管是什么名称,都会运行在由流动的、非确定性的基础架构支持的服务器上
  • 正常工作时会简化复杂的事物
  • 有几个相关的主题:基础架构管理、批处理、访问控制、定义、扩展和依赖关系

从第一篇文章发表以来,我拓展了自己最初的观察,将函数的定义重写为一系列属性。

函数是:

  • 无状态的
  • 短暂的
  • 自动扩展的
  • 单一用途的

函数是无状态的,因为它们不依赖内部存储器、状态机、存储的文件或挂载的卷。根据外部服务,对函数的每次调用应导致相同的最终结果。函数不必严格幂等,但在严格幂等时更易管理。

函数是短暂的,因为在任何时候都可以用相同的副本替换它们,而不会影响行为。这一属性意味着我们可以用相同的方式管理所有函数——检查函数的运行状况、查看它们的生命周期、日志记录,乃至监控工作等都可以用同一种方法来处理。

函数能自动从最小副本数扩展到最大副本数,甚至自动降到零并再次扩展上来,以匹配需求或节省资源。

函数是单一用途的,但必须以常识为准。我们用不着每次在代码中编写 function x() {} 或 def x: 时都创建一个新的 FaaS 函数。函数的单一用途可能是“一条员工记录的 CRUD”“格式化此 IBAN”或“使用机器学习模型识别此图像的内容”。

只要你编写了至少一个无服务器函数,那么你就会意识到入口点往往已经从你那里抽象出来了。你只需编写一个处理程序——然后所有依赖项都以一种通用格式表示,例如 Node.js 的 package.json 或 Python 的 requirements.txt 文件。

下面是一个 Node.js 函数的示例:

复制代码
"use strict"
module.exports = (context, callback) => {
callback(undefined, {status: "done"});
}

作为开发人员,你用不着了解用于引导处理程序的机制——这是无聊的重复性细节,你可以让 FaaS 框架或工具包来操心这些事情。
我们看到了类似的抽象模式,也看到了诸如 Sinatra、Django 和 Express.js 之类的微服务框架中隐藏无聊细节的现象。一种尺寸很少能满足所有需求,因此每种语言或运行时都有多种选择。

什么是无状态微服务?

无状态微服务是一种微服务,它可以像 FaaS 函数一样进行部署,并可以通过 FaaS 框架或 OpenFaaS 这样的平台来管理。因此,在 OpenFaaS CLI、Gateway API 或 UI 中不需要特殊的路由(route)、标志(flag)或过滤器(filter)。

OpenFaaS的无状态微服务介绍

就 OpenFaaS 组件而言,函数可以用任何语言编写并打包在 Docker 映像中。它必须通过 8080 端口上的 HTTP 提供内容,并将锁定文件写入 /tmp/.lock。如果你的函数或服务检测出自身的异常,那么你可以删除锁定文件,OpenFaaS 将重新启动 / 重新安排你的函数。

OpenFaaS 有一个 Ruby 语言模板,可用于创建 Ruby FaaS 函数。Ruby 无状态微服务是使用 https://rubyonrails.org/ ]( https://rubyonrails.org/ ">Ruby on Rails(、Sinatra 或其他 Ruby 微服务框架创建的 Ruby 微服务。其中的主要区别在于,与 FaaS 函数相比你要做的工作更多了。现在,你必须管理自己的 Dockerfile、状况检查和路由。

Sinatra 是 Ruby 的 DSL 或框架,用于快速构建微服务。

下面是官方网站上的 hello-world 示例:

复制代码
require 'sinatra'
get '/frank-says' do
'Put this in your pipe & smoke it!'
end

如果我们将该文件另存为 main.rb 并运行 gem install sinatra,然后运行 ruby main.rb,则将在默认端口 5678 上启动一个 Web 服务器,然后可以跳转至 URL: http://127.0.0.1:5678/frank-says 上。

OpenFaaS CLI 可以模板化、构建和部署这个微服务。然后,OpenFaaS 平台将跟踪这个微服务的调用指标,并将其自动放大、缩小甚至降为零并再次放大。

创建 Sinatra 无状态微服务

下面我们来使用 Sinatra 创建一个无状态微服务。

你首先需要准备一些工具:

  • 适用于 Mac/Linux/Windows 的 Docker
  • 一个 Docker Hub 帐户,或其他 Docker 仓库的帐户
  • OpenFaaS 和 CLI——可选 Kubernetes 或 Swarm

创建一个 Hello World 服务

首先创建一个新文件夹并生成一个 dockerfile 函数。其中 dockerfile 模板会告诉 OpenFaaS CLI,在不应用其他任何脚手架或模板的情况下运行 Docker 构建,你必须提供自己的 Dockerfile。

复制代码
$ mkdir -p sinatra-for-openfaas/ \
&& cd sinatra-for-openfaas/
$ faas-cli new --prefix=alexellis2 --lang dockerfile frank-says

用你的 Docker Hub 帐户或另一个 Docker 仓库替换 alexellis2。一个 Docker 映像将被推送到这里,这是 build/faas-cli up 命令的一部分。

这将创建两个文件,就像你用 faas-cli new 上列出的一种语言创建函数时一样:

复制代码
./frank-says/Dockerfile
./frank-says.yml

创建一个 Gemfile 和 main.rb 文件:
./frank-says/main.rb:

复制代码
require 'sinatra'
set :port, 8080
set :bind, '0.0.0.0'
open('/tmp/.lock', 'w') { |f|
f.puts "Service started"
}
get '/' do
'Frank has entered the building'
end
get '/logout' do
'Frank has left the building'
end

有关 OpenFaaS 负载的注意事项:

  • 它们必须绑定到 TCP 端口 8080
  • 准备接收流量时,它们必须写一个文件 /tmp/.lock。

./frank-says/Gemfile:

复制代码
source 'https://rubygems.org'
gem "sinatra"

可以在此文件中添加任意 gems 列表。
现在将./frank-says/Dockerfile 替换为:

复制代码
FROM ruby:2.4-alpine3.6
WORKDIR /home/app
COPY . .
RUN bundle install
RUN addgroup -S app \
&& adduser app -S -G app
RUN chown app:app -R /home/app
WORKDIR /home/app
HEALTHCHECK --interval=5s CMD [ -e /tmp/.lock ] || exit 1
USER app
CMD ["ruby", "main.rb"]

Dockerfile 执行以下操作:

  • 添加非 root 用户
  • 添加 Ruby 源代码和 Gemfile,然后安装 sinatra gem
  • 添加一个间隔为 5 秒的健康检查
  • 设置启动命令

部署示例

现在你已经做好了准备,可以使用 OpenFaaS CLI 构建和部署示例了。

  • 使用你的帐户详细信息登录
复制代码
$ docker login
  • 运行 up 命令,该命令是 build、push 和 deploy 的别名。
复制代码
$ faas-cli up --yaml frank-says.yml
Deploying: frank-says.
Deployed. 200 OK.
URL: http://127.0.0.1:8080/function/frank-says

使用 curl 调用你的微服务,或在 Web 浏览器中查看它:

复制代码
$ curl http://127.0.0.1:8080/function/frank-says/
Frank has entered the building.

你也可以尝试自定义路径:

复制代码
$ curl http://127.0.0.1:8080/function/frank-says/logout
Frank has left the building.

你可以尝试更新消息或添加其他路由,然后再次运行 faas-cli 以重新部署微服务。
现在检查 faas-cli list,能看到每次访问微服务时调用计数会随之增加。

复制代码
$ faas-cli list
Function Invocations Replicas
frank-says 5 1

触发自动扩展

现在,我们可以使用简单的 bash for 循环来触发自动扩展:

复制代码
$ for i in {1..10000}
do
sleep 0.01 \
&& curl http://127.0.0.1:8080/function/frank-says \
&& echo
done

在另一个窗口中输入:watch faas-cli list 或者定期运行 faas-cli list 。自动扩展生效后,你应该能看到 Invocations 的值增加,并且 Replicas 值也会增加。

复制代码
Function Invocations Replicas
frank-says 702 4

当 bash for 循环完成或使用 Ctrl + C 取消它时,你会看到副本数减少到 1。
你也可以在以下网址使用 OpenFaaS UI 监视和调用微服务: http://127.0.0.1:8080

OpenFaaS的无状态微服务介绍

阅读有关自动扩展的更多信息,包括如何配置最小、最大和零副本缩放参数

部署带有 MySQL 的 Sinatra 留言簿

复制代码
$ git clone https://github.com/openfaas-incubator/openfaas-sinatra-guestbook \
&& cd openfaas-sinatra-guestbook

在./sql.yml 中配置你的 MySQL 数据库细节。如果你还没有 MySQL,那么只需花几分钟使用 Kubernetes 上的 helm 或 docker run,以及官方 Docker 映像就能部署完毕。

复制代码
$ cp sql.example.yml sql.yml

最后部署留言簿:

复制代码
$ faas-cli up
http://127.0.0.1:8080/function/guestbook

使用上面命令提供的 URL 来访问微服务。
在 UI 中登录留言簿,完成后,你可以随时发布到 /function/guestbook/reset 来重置 MySQL 表。

OpenFaaS的无状态微服务介绍

留言簿代码的状态存储在 MySQL 表单中,这意味着它可以随时重新启动而不会丢失数据。这是 FaaS 函数和无状态微服务的一个关键属性。如果 OpenFaaS 添加了我们代码的其他副本——每个副本都将具有相同的环境视图,因为它依赖于外部数据库来获取其数据。

启用零缩放

要启用缩放到零的功能,只需按照文档说明启用 faas-idler。

然后在你的 stack.yml 文件中添加一个标签,以告知 OpenFaaS 你的函数可以进行零缩放:

复制代码
labels:
com.openfaas.scale.zero: true

最后,通过 faas-cli up 重新部署留言簿。一旦检测到空闲状态,faas-idler 现在会将你的函数缩放到零副本。默认的空闲时间设置为 5 分钟,可以在部署时配置。
回到 Sid 最初的问题,我们已经部署了一个用 Ruby 编写的无状态微服务,该服务将在空闲时缩放到零,还能及时扩展以服务流量。管理它的方式与我们现有的 FaaS 函数完全相同,这意味着你可以专注于构建重要的内容,而不必操心 Kubernetes 或 Docker Swarm 的内部细节。

总结

现在,我们已经使用 MySQL、ebs 视图、Bootstrap 和 Sinatra 部署了一个简单的 hello-world Sinatra 服务和一个更完整的留言簿示例。接下来你就可以开始使用 OpenFaaS 简化开发人员工作流程了——你可以使用 FaaS 函数,或者简化微服务的管理工作。

作者介绍:
Alex Ellis(alex@openfaas.com)是 @openfaas 的创始人。

原文链接 https://www.openfaas.com/blog/stateless-microservices/

评论

发布