本文作者 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 函数的示例:
作为开发人员,你用不着了解用于引导处理程序的机制——这是无聊的重复性细节,你可以让 FaaS 框架或工具包来操心这些事情。
我们看到了类似的抽象模式,也看到了诸如 Sinatra、Django 和 Express.js 之类的微服务框架中隐藏无聊细节的现象。一种尺寸很少能满足所有需求,因此每种语言或运行时都有多种选择。
什么是无状态微服务?
无状态微服务是一种微服务,它可以像 FaaS 函数一样进行部署,并可以通过 FaaS 框架或 OpenFaaS 这样的平台来管理。因此,在 OpenFaaS CLI、Gateway API 或 UI 中不需要特殊的路由(route)、标志(flag)或过滤器(filter)。
就 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 示例:
如果我们将该文件另存为 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。
用你的 Docker Hub 帐户或另一个 Docker 仓库替换 alexellis2。一个 Docker 映像将被推送到这里,这是 build/faas-cli up 命令的一部分。
这将创建两个文件,就像你用 faas-cli new 上列出的一种语言创建函数时一样:
创建一个 Gemfile 和 main.rb 文件:
./frank-says/main.rb:
有关 OpenFaaS 负载的注意事项:
它们必须绑定到 TCP 端口 8080
准备接收流量时,它们必须写一个文件/tmp/.lock。
./frank-says/Gemfile:
可以在此文件中添加任意 gems 列表。
现在将./frank-says/Dockerfile 替换为:
Dockerfile 执行以下操作:
添加非 root 用户
添加 Ruby 源代码和 Gemfile,然后安装 sinatra gem
添加一个间隔为 5 秒的健康检查
设置启动命令
部署示例
现在你已经做好了准备,可以使用 OpenFaaS CLI 构建和部署示例了。
使用你的帐户详细信息登录
运行 up 命令,该命令是 build、push 和 deploy 的别名。
使用 curl 调用你的微服务,或在 Web 浏览器中查看它:
你也可以尝试自定义路径:
你可以尝试更新消息或添加其他路由,然后再次运行 faas-cli 以重新部署微服务。
现在检查 faas-cli list,能看到每次访问微服务时调用计数会随之增加。
触发自动扩展
现在,我们可以使用简单的 bash for 循环来触发自动扩展:
在另一个窗口中输入:watch faas-cli list 或者定期运行 faas-cli list 。自动扩展生效后,你应该能看到 Invocations 的值增加,并且 Replicas 值也会增加。
当 bash for 循环完成或使用 Ctrl + C 取消它时,你会看到副本数减少到 1。
你也可以在以下网址使用 OpenFaaS UI 监视和调用微服务:http://127.0.0.1:8080
阅读有关自动扩展的更多信息,包括如何配置最小、最大和零副本缩放参数
部署带有 MySQL 的 Sinatra 留言簿
在./sql.yml 中配置你的 MySQL 数据库细节。如果你还没有 MySQL,那么只需花几分钟使用 Kubernetes 上的 helm 或 docker run,以及官方 Docker 映像就能部署完毕。
最后部署留言簿:
使用上面命令提供的 URL 来访问微服务。
在 UI 中登录留言簿,完成后,你可以随时发布到/function/guestbook/reset 来重置 MySQL 表。
留言簿代码的状态存储在 MySQL 表单中,这意味着它可以随时重新启动而不会丢失数据。这是 FaaS 函数和无状态微服务的一个关键属性。如果 OpenFaaS 添加了我们代码的其他副本——每个副本都将具有相同的环境视图,因为它依赖于外部数据库来获取其数据。
启用零缩放
要启用缩放到零的功能,只需按照文档说明启用 faas-idler。
然后在你的 stack.yml 文件中添加一个标签,以告知 OpenFaaS 你的函数可以进行零缩放:
最后,通过 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/
评论