Google Cloud Platform 的 Serverless 实验:第一部分





5.00/5 (1投票)
桌面程序员编写的简单云函数
引言
我开始试验 Cloud Functions,并成功地解决了我认为初学者可能会感兴趣的几个问题。请相信我,我不是专家。
背景
当我决定编写第一个小型自定义服务时,标准很明确:简单且我能不时通过连接互联网的设备访问的功能。
事实上,在许多通用场景中,存在类似 IFTTT 的在线解决方案,您无需编写自己的代码,只需进行组合和配置。但有时,别无选择,只能编写一些特定的内容。
1. 选择平台
我研究了现有的各种云平台(如 Amazon Web Service、Microsoft Azure、IBM Cloud、Heroku 等;还有很多,即使您只需要文件存储功能),并选择了 Google Cloud Platform (GCP)。以下是我考虑的因素。
1.1. 定价
GCP 允许在不租用对我而言不必要且昂贵的、全天候运行的服务器的情况下运行功能,您只需为真正需要的资源(如计算时间或磁盘空间)付费。一些云服务是完全免费的,一些则仅在使用量大大增加时才收费,而我永远不会达到该使用量(实际上,“除了 200 万次调用外,免费套餐还提供 400,000 GB-秒,200,000 GHz-秒的计算时间” https://cloud.google.com/functions/pricing)。
在一年的试用期内,我获得了 300 美元的预算,可以自由使用(有一些限制,例如不能用于挖比特币 https://cloud.google.com/terms/free-trial/),但在我的特定情况下,我没有花费其中的任何一部分。然而,试用期结束后,GCP 的计费逻辑可能会发生变化,请参阅 2.2 中的存储桶注意事项。
查看其他云提供商的价格列表,根据您的需求选择平台。
命名可能不同,Google 或 Microsoft 称之为 Functions,而 Amazon 称之为 Lambda。
如果您需要持久化存储,一个提供商通常会提供更多解决方案,从文件到数据库,价格也各不相同。
尝试切换到另一个提供商,您可能会错过一些您习惯的功能。
1.2. Web 访问
GCP 允许访问其他网站。在云平台上,此类功能可能仅限于付费版本(顺便说一句,“即使是免费套餐的使用,我们也需要一个有效的账单账号” https://cloud.google.com/functions/pricing),但在我的 GCP 试用期间,我从未遇到过收费(实际上,“每月 5GB 的互联网传出流量”以下均免费 https://cloud.google.com/terms/free-trial/)。
1.3. 编程
各种平台通常支持多种语言。
在 Google 的产品中,我选择了 Node.JS (JavaScript),因为它很简单。对于简单的场景(我将展示一些示例),GCP 提供了一个名为 Inline editor 的在线 Node.JS 编辑器。
GCP 初学者不需要从命令行开始,云配置可以在 GUI(所谓的控制台)中完成。
2. Hello World 示例
像我这样的 Node.JS 新手打开 Google 的教程 https://cloud.google.com/functions/docs/quickstart,当进行到第四步时,会觉得开始变得太复杂了。
幸运的是,有更简单的方法。
2.1. 环境
首先注册一个免费试用 https://cloud.google.com/free/。注册时,会要求您提供银行卡和手机号码。
之后,只需进入您的 GCP 控制台 http://console.cloud.google.com/。
在那里,创建一个新的 **项目**。它会获得一个内部 ID,类似于 ProjectName-123456
,最终必须连接到连接到您银行卡的 **账单**。**账单** 和此处提到的其他控制台部分通常在控制台的 **主页** 左侧可见。
进入您的项目后,在 **Cloud Functions**(不一定是 **API Manager**)中,启用项目上的 **Cloud Functions API**。
每一步都需要几秒钟。
2.2. Hello World 函数
转到 **Cloud Functions**(如果您还没有),然后选择 **Create Function**。
您必须选择一个项目唯一的函数名称。名称以后无法更改,如果不喜欢,必须复制然后删除原始函数。您将在项目函数列表中看到该名称。
选择 **HTTP Trigger** 选项。这意味着您可以通过类似 https://us-central1-ProjectName-123456.cloudfunctions.net/FunctionName 的方式调用函数(您的确切 URL 显示在 **Trigger** 下方),在 Web 浏览器或其他软件中访问它。
这意味着任何人都可以通过做同样的事情来调用它。在最初的两次调用后,它会影响您的 **账单**。这就是为什么在 **账单**(**Cloud Functions** 之外)中,您可以设置 **Budget & Alerts**。在某些服务中,可以设置自己的额外限制。
对于简单的功能,您可以选择最少可能的 **Memory allocated**。设置较短的 **Timeout**,这样如果您的函数卡住,您就不必等待一分钟。
然后,有必要处理 **Source code**。设置 **Inline editor** 选项,选择 index.js(两者都应预先选中),您就能看到这段预定义的默认脚本。
/**
* Responds to any HTTP request that can provide a "message" field in the body.
*
* @param {!Object} req Cloud Function request context.
* @param {!Object} res Cloud Function response context.
*/
exports.helloWorld = function helloWorld(req, res) {
// Example input: {"message": "Hello!"}
if (req.body.message === undefined) {
// This is an error case, as "message" is required.
res.status(400).send('No message defined!');
} else {
// Everything is okay.
console.log(req.body.message);
res.status(200).send('Success: ' + req.body.message);
}
};
如果您不知道为什么是 200 或 400,请在此处查看 HTTP 状态码列表 here。
如您所见,脚本包含一个导出的函数 helloWorld
。您还必须在 **Function to execute** 项目中具有相同的 helloWorld
。
选择 **Stage bucket**,这是您的代码将存储的地方。
您可以在 **Storage** 中预先 **Create Bucket**。但在 **Create Function** 中,您也可以在 **Browse** 中创建 **New bucket**。
下次,只需 **Browse** 并 **Select** 现有项。
根据 Cloud Storage Always Free Usage Limits https://cloud.google.com/storage/pricing#cloud-storage-always-free,每月 5 GB-月的 **Regional storage** 应该免费。“Cloud Storage Always Free quotas apply to usage in us-west1, us-central1, and us-east1 regions. If you go over these usage limits and are no longer in the free trial period, you are charged according to the price sheet below.”
您可以稍后将函数移至不同的存储桶。**Edit**(编辑)现有函数,然后 **Select**(选择)新存储桶。但请记住,您函数的前一个版本(版本)仍保留在原始存储桶中。实际上,每次 **Edit** 都会创建一个新的存储桶文件,保留旧的、已不再使用的文件。您可以小心地在 **Cloud Functions** 之外,在 **Storage**, **Browse** 下删除未使用的文件。
最后,按下 **Create**(创建)按钮,一段时间后函数就会出现在列表中。绿色图标表示成功,红色图标表示失败,例如因为脚本与 **Function to execute** 不匹配。
成功后,在新的浏览器标签页中打开您的 https://us-central1-ProjectName-123456.cloudfunctions.net/FunctionName (您的实际触发链接会不同),您应该会看到预期的输出。
No message defined!
从控制台的函数列表中打开您的函数,然后进入其 **Testing**(测试)选项卡。在 **Triggering event**(触发事件)中,粘贴我从脚本注释中复制的 JSON 格式(JavaScript Object Notation)的输入
{"message": "Hello!"}
或者相同的格式,但分成了更多行
{
"message": "Hello!"
}
然后按下 **Test the function**(测试函数)按钮。**Output**(输出)应该是
Success: Hello!
现在尝试使用 https://us-central1-Projectname-123456.cloudfunctions.net/FunctionName?message=Hello! ,尽管有 ?message=Hello!
,结果仍然是...
No message defined!
...一样。这是因为脚本评估了 req.body.message
,它对应于 http 方法 post。当您想响应 URL 中指定的参数(http 方法 get)时,您会在 req.query.message
中找到它。
3. HTML 表单
创建第二个函数。步骤与创建第一个函数类似,只不过现在您可以从现有函数的上下文菜单(函数列表中的三个垂直点)开始,然后选择 **Copy**(复制)来创建它。
选择一个新的项目唯一函数名称,然后输入如下所示的 **Source code**。
/**
* callHelloWorld
*
* @param {!Object} req Cloud Function request context.
* @param {!Object} res Cloud Function response context.
*/
exports.callHelloWorld = function callHelloWorld(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(
'<html><form action="helloWorld" method="post">' +
'Message: <input type="text" name="message"><br>' +
'<input type="submit" value="Send"></form></html>');
res.end();
};
在浏览器中打开函数的触发器,会显示一个带有表单的 HTML 页面,允许您键入消息内容,在按下 **Send**(发送)按钮后,它将使用 **method post** 调用 **helloWorld** 函数。
此版本要求两个函数都在同一个存储桶和存储桶文件夹中,否则您必须修改 **action** 以指向被调用的函数(**action** 也可以是完整的 URL)。
4. HTTP 请求
这是第三个函数示例
/**
* requestFunction
*
* @param {!Object} req Cloud Function request context.
* @param {!Object} res Cloud Function response context.
*/
exports.requestFunction = function requestFunction(req, res) {
//based on https://www.sitepoint.com/making-http-requests-in-node-js/
var request = require("request");
request({
uri: "http://www.random.org/integers/?num=1&min=1&max=10&col=1&base=10&format=plain&rnd=new",
headers: {'User-Agent': 'request'},
method: "GET",
}, function(error, response, body) {
res.status(200).send('Success: ' + error + "&" + response.statusCode + "&" + body + ' end');
});
};
脚本使用 request
对象访问 random.org 的 URL(好的,URI),并在回调函数中显示返回的文本正文。修改此示例以调用您的云函数很容易。
有关 request 的更多信息,请参见 here。
要使用 request 对象,必须将 request 模块包含到我们的函数的包中。在编辑器中,从 index.js 切换到 package.json,然后在此处添加依赖项。
{
"name": "sample-http",
"version": "0.0.1",
"dependencies": {
"request": "^2.81.0"
}
}
问题是我如何获得 request
模块的版本。
5. Google Cloud Shell
在控制台的顶部工具栏中按下 **Activate Google Cloud Shell**(激活 Google Cloud Shell)按钮。之后,当它显示 Linux 命令 shell 时(为了让我相信您,请尝试 cat /etc/*{release,version}
命令)。
运行 dir
或 ls
。输出应为
node_modules README-cloudshell.txt
现在调用 cd node_modules
,然后在其中执行 ls
。您会看到一个预装模块列表,其中也包含 request
。cd request
,ls
,然后 cat package.json
- 实际的 request
版本就在那里。
随心所欲地使用 cd ..
或简单地使用 exit
。
以上是我关于 Cloud Shell 的全部内容。
第一部分结束。在第二部分中,我计划发送和接收电子邮件。