通过 Jets 框架在 AWS Lambda 上实现无服务化 Ruby

阅读数:19344 2019 年 6 月 5 日 09:17

通过Jets框架在AWS Lambda上实现无服务化Ruby

本文将构建一个 SMS 应用。为了让其更加有趣,本文将加入一些幽默元素。当用户在应用中打字时,它将会回复您一个由 icanhazdadjoke API 免费提供的笑话。该应用会展示如何上手 Jets,以及创建控制器、动作和线路。我们将构建一个单端点,当某个号码接收到 SMS 信息时,这个端点会对来自 Twilio 的 HTTP 请求做出反应。端点每次都会返回 TwiML ,以及一个随机的、令人爆笑的笑话。

通过Jets框架在AWS Lambda上实现无服务化Ruby

当 AWS 在 2014 年发布 Lambda 时,没有支持 Ruby,而 Python、Node.js 和 Java 等平台开始了针对云托管和云运行功能的无服务化革命。在 2018 年底,对 Ruby 的支持终于发布。

开发者可以使用原始功能和无服务应用模型(SAM) 模板,通过Ruby on Lambda 构建任何东西,正如《 Ruby on Lambda 的开始指南》中描述的那样。但是,Ruby 的主要目的在于让开发者更快乐,而不是更痛苦。因为,当配置文件比程序还长时,整个流程可以说会让人非常痛苦。 Jets 框架是一个利用 Ruby 来让无服务化更加快乐的框架。

通过Jets框架在AWS Lambda上实现无服务化Ruby

从 Rails 过渡到 Jets

Jets 将构建 Rails 应用体验和部署 AWS Lambda,并和相关服务能力加以结合。相关服务包括:API Gateway, S3 和 DynamoDB。在本帖中,我们将看看如何使用 Jets 并部署一个基于 Lambda、用 Ruby 编写的的 Twilio 应用。

我们构建的是什么

为了简便,我们将要构建一个 SMS 应用。而且,为了让其更加有趣,我们还将加入一些幽默元素。当你在该应用中打字时,它将会回复一个笑话,由 icanhazdadjoke API 免费提供。

这个应用会向我们展示如何上手 Jets,以及如何创建控制器、动作和线路。我们将构建一个单端点,当某个号码接收到 SMS 信息时,这个端点会对来自 Twilio 的 HTTP 请求做出反应。每次,这个端点会返回 TwiML ,以及一个随机的、令人爆笑的笑话。

需要什么

为了完成这个项目,开发者需要准备:

开始

首先,全局安装 jets gem。在命令行中键入:

复制代码
gem install jets

然后,Jets 可执行文件就可以被当做生成器使用,如同 Rails,用来发起一个新项目,并运行该项目中的命令。我们现在会创建一个新项目,但是鉴于本帖子的范围有限,我们会对该项目适当进行限制。首先,我们将在 API 模式下创建项目,因为在这个应用中,我们不需要 HTML 视图。而且,我们也无需通过 webpacker 来进行资产编译,所以,这会节省我们的构建时间。我们也不需要数据库。运行以下命令,创建一个新的项目:

复制代码
jets new dad-jokes-sms --mode api --no-database

在生成器完成运行后,切换到 dad-jokes-sms 目录下,运行以下命令,以本地运行你的应用:

复制代码
jets serve

打开 http://localhost:8888 ,你会看到以下的页面:

通过Jets框架在AWS Lambda上实现无服务化Ruby

如果看到了这个页面,说明新 Jets 项目运行成功。

第一个 Jets 控制器

现在已经有了 Jets 应用,因此可以使用 gem 来生成应用部件,从模型和控制器到完整架构。对于应用来说,需要只有一个动作的控制器。怎么生成它呢?运行以下命令:

复制代码
jets generate controller Messages create

生成器将创建和编辑一些文件。开发者需要检查新的路径,因此请打开 config/routes.rb。

Jets 生成了一个 GET 线路,但是 Twilio webhook 会默认生成 POST 请求,而我宁可让它保持现在这样。设置应用,使之在 /messages 端点上接收 POST 请求 webhook,像这样:

复制代码
Jets.application.routes.draw do
post 'messages', to: 'messages#create'
root "jets/public#show"

jets/public#show 控制器可以提供来自公共文件夹的静态 utf8 内容。注意,作为部署流程的一部分,Jets 会将公共文件夹下的文件上传到 s3 中,并且从 s3 中直接提供这些文件。S3 非常适合提供静态资产。此处有更多信息: http://rubyonjets.com/docs/assets-serving/

复制代码
any "*catchall", to: "jets/public#show"
end

现在,让我们编写控制器的动作。打开 app/controllers/messages_controller.rb,你会看到“创建”动作的方法。这一动作会接收 Twilio webhook,并用 TwiML 进行回复,且返回一个笑话。

获取笑话

为了返回笑话,我们需要对 icanhazdadjoke API 进行调用。让我们快速写一个能够实现这一目标的私有方法。

我们将使用 open-uri,因为它在发送简单的 web 请求方面(包括下载文具和图片)十分有用。Jets 生成了一个 GET 路径,但是 Twilio webhook 会默认生成 POST 请求,而我宁可让它保持这样。在 MessagesController 中加入以下内容:

复制代码
require 'open-uri'
class MessagesController < ApplicationController
def create
end
private
def random_joke
open('https://icanhazdadjoke.com/', { 'Accept' => 'text/plain' }).read
end
end

现在,可以将笑话以 TwiML 的形式返回给 Twilio。

返回 TwiML

我们将构建一个回复,方法是使用来自 twilio-ruby 助手库中的助手程序。打开 Gemfile,添加 twilio-ruby:

复制代码
source "https://rubygems.org"
gem "jets"
gem "twilio-ruby"

在命令行中运行 bundle install,以安装 gem。在 create 动作中,实例化一个新的 TwiML 回复对象,使用 TwiML element 来回复进来的消息,并提供 XML 回复,方法如下:

复制代码
require 'open-uri'
class MessagesController < ApplicationController
def create
twiml = Twilio::TwiML::MessagingResponse.new
twiml.message body: random_joke
render xml: twiml.to_xml
end
private
def random_joke
open('https://icanhazdadjoke.com/', { 'Accept' => 'text/plain' }).read
end
end

要知道更多关于如何使用 twilio-ruby 助手库来生成 TwiML 的信息,请阅读文档。
我们可以在本地运行以测试是否可得到预期回复。如果应用停止,请运行 jets serve 重启。使用 curl 向 localhost:8888/messages 发送 POST 请求,你便会在 TwiML 回复中看到由 icanhazdadjoke 提供的笑话。

复制代码
curl --data "" http://localhost:8888/messages
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>What’s the advantage of living in Switzerland? Well, the flag is a big plus.</Message>
</Response>

非常好,Jets 开始工作了!现在我们要把它部署到 AWS Lambda 中。

要将 Jets 应用部署到 AWS,首先需要设置好项目和证书,以便让它可以访问 AWS 服务。一个比较好的做法是创建拥有其工作所需最少权限的用户, Jets 文档描述了用户需要的最少权限。在 AWS 账户中创建一个策略,该策略包含所有这些权限。此外,还要创建一个新用户,该策略将被分配给这个用户。然后,就可以使用该用户的证书来部署应用。

AWS 控制面板中,找到 IAM 服务,或者直接跳到 IAM部分

通过Jets框架在AWS Lambda上实现无服务化Ruby

跳转到 Policies 部分,并创建一个新的策略。

通过Jets框架在AWS Lambda上实现无服务化Ruby

选择 JSON 选项卡,输入来自 Jets 文档的以下 JSON:

复制代码
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"apigateway:*",
"cloudformation:*",
"dynamodb:*",
"events:*",
"iam:*",
"lambda:*",
"logs:*",
"route53:*",
"s3:*"
],
"Resource": [
"*"
]
}
]
}

继续点击,检查该策略,并命名。

通过Jets框架在AWS Lambda上实现无服务化Ruby

保存策略。现在,需要创建一个新用户,并且将策略添加给该用户,并给予该用户创建 Jets 需要部署的资源的权限。打开 IAM 控制面板中的 Users 部分,创建一个新用户。

通过Jets框架在AWS Lambda上实现无服务化Ruby

给该用户命个名,再在 Access Type 中选择 Programmatic Access。

通过Jets框架在AWS Lambda上实现无服务化Ruby

点击 Next,并选择给予该新用户的权限。选择 Attach existing policies directly,并筛选刚刚创建的策略。选择该策略,并点击 Next。

通过Jets框架在AWS Lambda上实现无服务化Ruby

点击 Next,直到成功页面出现为止。

通过Jets框架在AWS Lambda上实现无服务化Ruby

保存最终页面上显示的 Access key ID 和 Secret access key。在部署的时候,我们要用到它们。现在,我们已经做好部署准备。

在 Lambda 上进行部署

在命令行中输入:

复制代码
AWS_ACCESS_KEY_ID=YOUR_USER_KEY AWS_SECRET_ACCESS_KEY=YOUR_USER_SECRET_KEY jets deploy

Jets 将把证书作为环境变量来设置 AWS 账户中的所有资源,以方便应用运行。这会花费一些时间,但是完成后,你会得到一个 URL,而且应用会在上面运行。

通过Jets框架在AWS Lambda上实现无服务化Ruby

你会注意到应用被部署到一个“开发”环境中。要知道更多关于 Jets 如何处理环境的信息,请阅读文档。

现在可以用 curl 来测试这个 URL。记住,我们使用了 /messages 这条线路,所以务必在 API 网关端点末端加上它,并且发出一个 POST 请求。

复制代码
$ curl --data "" https://YOUR_API_GATEWAY_ENDPOINT/messages
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Message>I knew a guy who collected candy canes, they were all in mint condition</Message>
</Response>

现在,我们便可以随时收到笑话了,让我们把它与 Twilio 号码连接起来。

通过 SMS 发送笑话

访问 Twilio 控制面板,转到有效电话号码。如果你已经有一个号码,请编辑它,否则,请购买一个可以接收SMS 信息的新号码。在 A message comes in字段中,输入你的应用 URL。

通过Jets框架在AWS Lambda上实现无服务化Ruby

保存号码,并向其发送一条信息,应该会在回复中得到一个笑话。

无服务化有趣的事情

在本帖中,我们见证了如何使用 Jets 来编写 Ruby 应用,并将它部署到 AWS Lambda 中。你可以在 GitHub 上看到完整的项目

Jets 能帮助完成的东西远不止这些,譬如:对事件作出反应将数据储存到数据库中,甚至是运行你现有的 Rails 应用等等。阅读 Jets 文档中的这些文章,了解更多 Jets 的功能。

查看英文原文: Serverless Ruby on AWS Lambda with the Jets framework

收藏

评论

微博

用户头像
发表评论

注册/登录 InfoQ 发表评论