10分钟开发并部署一个函数计算服务

廖雪峰 / 文章 / ... / Reads: 21910 Edit

函数计算,是最近流行的一种全托管的计算服务。

作为编程语言的基本单元,函数对大多数开发人员来说,本身是非常简单的。例如,我们编写一个计算绝对值的JavaScript函数:

function abs(x) {
    if (typeof (x) !== 'number') {
        throw 'not a number';
    }
    return x < 0 ? -x : x;
}

这个函数编写非常容易,但是,如果作为服务,要把它部署到网络上,则需要大量的工作。

第一个问题是选择什么协议调用函数。可以选择HTTP协议或者gRPC协议,考虑到通用型,选择HTTP协议,并采用REST方式调用相对更加容易。

紧接着,就需要支持REST的服务器与对应的框架。例如,以JavaScript函数为例,就需要安装Node,以及选择一个Web框架,例如Express

最后,还需要自己编写路由、解析输入、调用函数并返回输出,只有完成了这一系列工作后,用户才能通过一个URL调用这个函数并获得返回值:

curl http://example.com/functions/abs?input=12345

无论函数多么简单,一旦涉及到上述开发部署流程,就非常让人头大。因此,越来越多的云服务商开始提供FaaS(Function as a Service)服务,即用户只定义函数,剩下的网络请求、负载均衡、虚拟机环境等全部由FaaS提供,能大大简化函数计算的开发。

本文的目标是从零开始部署一个头像服务,输入一个名字,例如bob,返回一个动态生成的SVG图像。以下是一个示例函数调用:

https://avatar.liaoxuefeng.com/.netlify/functions/avatar?name=bob

它返回的图像如下:

这个服务用JavaScript编写,并部署在Netlify上。后面我们会讨论为什么选择Netlify。

首先,我们在GitHub创建一个新的Git库netlify-avatar,它具有如下目录结构:

<repo>
├── netlify
│   └── functions
│       └── avatar.js
├── netlify.toml
├── package.json
└── public
    └── index.html

Netlify默认在netlify/functions目录下查找所有函数。我们放置了一个avatar.js,对应的函数名就是avatar,调用该函数的URL路径则是/.netlify/functions/avatar。接下来,我们在根目录编写一个netlify.toml描述文件:

[build]
  publish = "public/"
  command = "npm install"

[functions]
  directory = "netlify/functions/"
  node_bundler = "esbuild"

这个文件的详细说明可以参考Netlify文档,其中:

publish = "public/"指示静态文件存储的目录,这并不是必须的,但我们放一个index.html可以作为函数的描述页面;

command = "npm install"指示部署时运行的命令,此处是安装相关依赖包;

node_bundler = "esbuild"指示使用ES的import语法,因为Netlify不再支持require()语句。

接下来,我们把用到的依赖包用npm安装并保存到package.json中:

$ npm install --save minidenticons

最后,编写核心函数avatar.js

// 导入模块:
import { identicon } from 'minidenticons';

exports.handler = async function (event, context) {
    // 获取name输入:
    let name = event.queryStringParameters.name || 'unnamed';
    // 计算:
    let svg = identicon(name);
    // 返回结果:
    return {
        // HTTP 200:
        statusCode: 200,
        // 响应类型:
        headers: {
            'content-type': 'image/svg+xml'
        },
        // 响应文本:
        body: svg
    };
};

可见,核心函数是一个async function (event, context)event封装了所有输入,context则是函数的运行时环境,要求返回一个JavaScript Object,就可以完成函数的功能。

部署

要把上述函数部署到Netlify,首先使用GitHub账号登录到Netlify,创建一个Site,选择“Import an existing project from a Git repository”而不是“Start from a template”,因为我们并不需要部署复杂的Next.js。从GitHub选择对应的repo后,Netlify自动读取netlify.toml,点击部署,稍等一分钟左右,就可以通过Netlify提供的URL访问函数。最后,再绑定一个域名,勾选HTTPS支持,就完成了整个部署流程,非常简单。

后续如果修改了代码,则推送到GitHub后,会触发自动部署。

一般来说,无状态的服务非常适合作为函数服务运行,但很多时候,仍需要一些运行时配置,例如,防盗链设置、缓存时长等,这些可以通过环境变量实现,即在Netlify后台设置好环境变量,在函数中读取即可。

如果对比AWS的Lambda服务或者阿里云的FC服务,Netlify的部署无疑是最简单且最直接的,并且默认实现了代码推送即部署,无额外手动步骤。

本文源码可从GitHub下载。

GitHub

Comments

Make a comment

Author: 廖雪峰

Publish at: ...

关注公众号不定期领红包:

加入知识星球社群:

关注微博获取实时动态: