部署到阿里云函数计算
阿里云 Serverless 是国内最早提供 Serverless 计算服务的团队之一, 依托于阿里云强大的云基础设施服务能力,不断实现技术突破。目前,淘宝、支付宝、钉钉、高德等已经将 Serverless 应用于生产业务,云上的 Serverless 产品在南瓜电影、网易云音乐、爱奇艺体育、莉莉丝等数万家企业成功落地。
阿里云 Serverless 包含许多产品,如函数计算 FC,轻量应用引擎 SAE 等,本文主要使用了其 函数计算 部分。
下面是常见的函数触发器的使用、测试和部署方法。
部署类型
阿里云的函数计算部署类型比较多,根据运行的不同容器有以下几种。
名称 | 能力限制 | 描述 | 部署媒介 |
---|---|---|---|
内置运行时 | 不支持流式请求和响应;不支持太大的请求和响应入参 | 只能部署函数接口,不需要自定义端口,构建出 zip 包给平台部署 | zip 包部署 |
自定义运行时(Custom Runtime) | 可以部署标准应用,启动 9000 端口,使用平台提供的系统镜像,构建出 zip 包给平台部署 | zip 包部署 | |
自定义容器(Custom Container) | 可以部署标准应用,启动 9000 端口,自己控制所有环境依赖,构建出 Dockerfile 提供给平台部署 | Dockerfile 部署 |
在平台上分别对应创建函数时的三种方式。
纯函数开发(内置运行时)
下面我们将以使用 "内置运行时部署" 纯函数作为示例。
触发器代码
- Event
- HTTP
- API 网关
- Timer
- OSS
- MNS
发布不包含触发器的函数,这是最简单的类型,可以直接通过 event 手动触发参数,也可以在平台绑定其他触发器。
通过直接在代码中的 @ServerlessTrigger
装饰器绑定事件触发器。
import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core';
import { Context } from '@midwayjs/faas';
@Provide()
export class HelloAliyunService {
@Inject()
ctx: Context;
@ServerlessTrigger(ServerlessTriggerType.EVENT)
async handleEvent(event: any) {
return event;
}
}
阿里云的 HTTP 触发器和其他平台的有所区别,是独立于 API 网关的另一套服务于 HTTP 场景的触发器。相比于 API 网关,该触发器更易于使用和配置。
通过直接在代码中的 @ServerlessTrigger
装饰器绑定 HTTP 触发器。
import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core';
import { Context } from '@midwayjs/faas';
@Provide()
export class HelloAliyunService {
@Inject()
ctx: Context;
@ServerlessTrigger(ServerlessTriggerType.HTTP, {
path: '/',
method: 'get',
})
async handleHTTPEvent(@Query() name = 'midway') {
return `hello ${name}`;
}
}
API 网关在阿里云函数体系中比较特殊,他类似于创建一个无触发器函数,通过平台网关的绑定到特定的路径上。
import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core';
import { Context } from '@midwayjs/faas';
@Provide()
export class HelloAliyunService {
@Inject()
ctx: Context;
@ServerlessTrigger(ServerlessTriggerType.API_GATEWAY, {
path: '/api_gateway_aliyun',
method: 'post',
})
async handleAPIGatewayEvent(@Body() name) {
return `hello ${name}`;
}
}
定时任务触发器用于定时执行一个函数。
温馨提醒,测试函数后请及时关闭触发器自动执行,避免超额扣费。
import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core';
import { Context } from '@midwayjs/faas';
import type { TimerEvent } from '@midwayjs/fc-starter';
@Provide()
export class HelloAliyunService {
@Inject()
ctx: Context;
@ServerlessTrigger(ServerlessTriggerType.TIMER)
async handleTimerEvent(event: TimerEvent) {
this.ctx.logger.info(event);
return 'hello world';
}
}
事件结构
Timer 消息返回的结构如下,在 TimerEvent
类型中有描述。
{
triggerTime: new Date().toJSON(),
triggerName: 'timer',
payload: '',
}
OSS 用于存储一些资源文件,是阿里云的资源存储产品。 当 OSS 中有文件 创建,更新,对应的函数就会被触发而执行。
import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core';
import { Context } from '@midwayjs/faas';
import type { OSSEvent } from '@midwayjs/fc-starter';
@Provide()
export class HelloAliyunService {
@Inject()
ctx: Context;
@ServerlessTrigger(ServerlessTriggerType.OS)
async handleOSSEvent(event: OSSEvent) {
// xxx
}
}
事件结构
OSS 消息返回的结构如下,在 FC.OSSEvent
类型中有描述。
{
"events": [
{
"eventName": "ObjectCreated:PutObject",
"eventSource": "acs:oss",
"eventTime": "2017-04-21T12:46:37.000Z",
"eventVersion": "1.0",
"oss": {
"bucket": {
"arn": "acs:oss:cn-shanghai:123456789:bucketname",
"name": "testbucket",
"ownerIdentity": "123456789",
"virtualBucket": ""
},
"object": {
"deltaSize": 122539,
"eTag": "688A7BF4F233DC9C88A80BF985AB7329",
"key": "image/a.jpg",
"size": 122539
},
"ossSchemaVersion": "1.0",
"ruleId": "9adac8e253828f4f7c0466d941fa3db81161e853"
},
"region": "cn-shanghai",
"requestParameters": {
"sourceIPAddress": "140.205.128.221"
},
"responseElements": {
"requestId": "58F9FF2D3DF792092E12044C"
},
"userIdentity": {
"principalId": "123456789"
}
}
]
}
- 1、阿里云消息队列会对 Topic 和 Queue 产生一定的费用。
- 2、提供的默认消息队列格式为 JSON
import { Provide, Inject, ServerlessTrigger, ServerlessTriggerType } from '@midwayjs/core';
import { Context } from '@midwayjs/faas';
import type { MNSEvent } from '@midwayjs/fc-starter';
@Provide()
export class HelloAliyunService {
@Inject()
ctx: Context;
@ServerlessTrigger(ServerlessTriggerType.MQ)
async handleMNSEvent(event: MNSEvent) {
// ...
}
}
事件结构
MNS 消息返回的结构如下,在 FC.MNSEvent
类型中有描述。
{
"Context": "user custom info",
"TopicOwner": "1186202104331798",
"Message": "hello topic",
"Subscriber": "1186202104331798",
"PublishTime": 1550216302888,
"SubscriptionName": "test-fc-subscibe",
"MessageMD5": "BA4BA9B48AC81F0F9C66F6C909C39DBB",
"TopicName": "test-topic",
"MessageId": "2F5B3C281B283D4EAC694B7425288675"
}
触发器的更多配置由于和平台相关,将写在 s.yaml
中,如定时任务的时间间隔等,更多细节请查看下面的部署段落。
类型定义
FC 的定义将由适配器导出,为了让 ctx.originContext
的定义保持正确,需要将其添加到 src/interface.ts
中。
// src/interface.ts
import type {} from '@midwayjs/fc-starter';
此外,还提供了各种 Event 类型的定义。
// Event 类型
import type {
OSSEvent,
MNSEvent,
SLSEvent,
CDNEvent,
TimerEvent,
APIGatewayEvent,
TableStoreEvent,
} from '@midwayjs/fc-starter';
// InitializeContext 类型
import type { InitializeContext } from '@midwayjs/fc-starter';