无服务器框架 vs SAM vs AWS CDK
ℹ️ 编辑:这里有一个包含更多选项的更新版本
如今,在 AWS 上构建无服务器应用时,有几种不同的工具包可供使用,帮助您开发、测试和部署项目。无服务器框架 (Serverless Framework)长期以来一直占据主导地位,但AWS SAM和CDK近年来也越来越受欢迎。但是,哪一个最适合在新项目中使用,它们之间又有什么区别呢?毕竟,它们都只是生成 Cloudformation 模板的工具,不是吗?
为了了解每个选项的优点和缺点,我决定针对这三个选项构建一个相同的示例应用程序并比较这些方法。
在本文结束时,我希望您对无服务器框架、AWS SAM 和 CDK 有一个基本的了解,并且能够根据您的需求和偏好做出最适合您的下一个项目的明智选择。
我们的示例应用程序
为了保持趣味性,我们用来展示每个框架的应用绝对不是典型的 ToDo 应用——而是一个 ToDont 应用。用户可以向 API 网关发送一个 POST 请求,描述一些他们实际上不应该做的事情。Lambda 函数会获取 ToDont 项,并将其放入一个充当缓冲区的 SQS 队列中。最终,另一个 Lambda 函数会消费这个缓冲区队列,假装对该项目进行一些繁重的处理,并将其持久化到 DynamoDB 表中。
该应用程序架构简单易懂,但又足够“复杂”,足以与实际应用相媲美。为了保持代码简洁易读,有时不得不省略最佳实践和常识。所有配置均已完成且功能齐全,如果您想试用示例并自行部署应用,可以在此处找到代码和完整示例。
我们的 POST Lambda 函数如下所示
// src/post.js
const { SQS } = require('@aws-sdk/client-sqs');
const sqs = new SQS();
const handler = async (event) => {
console.log('event', event);
const { id, title } = JSON.parse(event.body);
await sqs.sendMessage({
QueueUrl: process.env.QUEUE_URL,
MessageBody: JSON.stringify({
id,
title,
})
});
return {
statusCode: '200',
};
};
module.exports = { handler };
进程 Lambda 看起来像这样
// src/process.js
const { DynamoDB } = require('@aws-sdk/client-dynamodb');
const { marshall } = require("@aws-sdk/util-dynamodb");
const ddb = new DynamoDB();
const handler = async (event) => {
console.log('event', event);
const tasks = event.Records.map((record) => {
const { id, title } = JSON.parse(record.body);
return ddb.putItem({
TableName: process.env.TABLE_NAME,
Item: marshall({
title,
id,
}),
});
});
return Promise.all(tasks);
};
module.exports = { handler };
先决条件
如果您想继续并部署应用程序,请注意以下事项:
-
下面的每个比较都假设您已在项目中安装了以下软件包作为依赖项
@aws-sdk/client-dynamodb
@aws-sdk/util-dynamodb
@aws-sdk/client-sqs
-
虽然下面的 Yarn 用作包管理器和脚本运行器,但您当然可以使用 NPM 和相应的命令。
-
所有示例都假设您已配置AWS 凭证默认配置文件
无服务器框架
无服务器框架(以下简称“Serverless”)已经存在很长时间了,并且一直是社区中很大一部分人的首选框架。它是一个简单的工具,抽象并简化了 CloudFormation 中许多繁琐的部分,并附带了许多简化应用测试和部署的功能。
运行 Serverless CLI 的首选方法是将其作为(开发)依赖项安装到项目中,只需运行yarn add serverless -D
以下命令即可。这样就只差一个serverless.yml
用于定义应用程序及其基础架构的文件了。完整的配置参考可以在这里找到,简而言之,serverless.yml 由两部分组成:
- 您的无服务器框架配置用于描述您的应用程序堆栈、AWS 环境和 lambda 函数
- 任何定义为 CloudFormation 资源的附加基础设施,例如我们的 DynamoDB 表和 SQS 队列。
我们的应用程序如下所示serverless.yml
。
// serverless.yml
service: sls-todont
provider:
name: aws
region: eu-north-1
runtime: nodejs14.x
environment: # Inject environment variables
TABLE_NAME: ${self:custom.tableName}
QUEUE_URL: !Ref todontsQueue
iamRoleStatements: # Configure IAM role statements
- Effect: Allow
Action: sqs:sendMessage
Resource: ${self:custom.queueArn}
- Effect: Allow
Action: dynamodb:putItem
Resource: ${self:custom.tableArn}
custom: # Custom variables that we can reference elsewhere
tableName: ${self:service}-table
queueName: ${self:service}-queue
tableArn: # Get ARN of table with CloudFormation helper
Fn::GetAtt: [todontsTable, Arn]
queueArn: # Get ARN of queue with CloudFormation helper
Fn::GetAtt: [todontsQueue, Arn]
functions: # Define our two Lambda functions
post:
handler: src/post.handler
events: # Invoke on post requests to /todonts
- http:
method: post
path: todonts
process:
handler: src/process.handler
events: # Consume SQS queue
- sqs:
arn: ${self:custom.queueArn}
# CloudFormation below to define our infrastructure resources
resources:
Resources:
todontsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.tableName}
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: 'PAY_PER_REQUEST'
todontsQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: ${self:custom.queueName}
现在要部署我们的应用程序,我们需要做的就是运行yarn serverless deploy
。
Serverless CLI 包含一些实用功能,可以通过运行yarn serverless logs --function process [--tail]
或使用 调用函数来打印或跟踪已部署函数的日志yarn serverless invoke --function process
。然而,在开发过程中,大多数情况下您不会调用该函数。相反,您可以让 Serverless 在本地模拟并运行这些函数,只需运行 即可yarn serverless invoke local --function post
。
➕优点
- 大型且乐于助人的社区
- 插件生态系统
- 简单的配置和简洁的变量支持
- 出色的调试和测试实用程序
➖缺点
- 大多数应用程序需要借助 CloudFormation 定义来处理基础设施的某些部分
- 难以共享配置和组件
- 仅限 YAML 配置。技术支持使用 JS 编写配置,但相关文档几乎不存在
- 我见过很多开发人员难以理解无服务器配置和 CloudFormation 配置之间的界限,或者为什么他们必须在文件中间更改语法
资源:
AWS SAM
与无服务器框架非常相似,SAM(或无服务器应用程序模型)是用于简化 CloudFormation 的抽象层和用于测试和部署应用程序的实用程序的 CLI 的组合。
以下是SAM CLI 的官方安装说明,该 CLI 会全局安装在您的系统上。SAM 使用一个samconfig.toml
文件来描述您的应用的相关信息,例如应用的名称、部署位置和部署方式,并使用另一个template.yml
文件来描述应用将使用的实际资源。
该template.yml
格式遵循CloudFormation模板解剖模板,但添加了一些字段。让我们看一下:
// template.yml
# Boilerplate to identify template as SAM template
AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: sam-todonts
Globals:
Function:
Runtime: nodejs14.x
Environment: # Inject environment variables
Variables:
QUEUE_URL:
Ref: TodontsQueue
TABLE_NAME:
Ref: TodontsTable
Parameters: # Parameters which can be filled by the CLI on deploy
TableName:
Description: Name of DynamoDB table
Type: String
Default: sam-todonts-table
QueueName:
Description: Name of SQS queue
Type: String
Default: sam-todonts-queue
Resources:
PostFunction:
Type: AWS::Serverless::Function
FunctionName: sam-todonts-post
Properties:
Handler: src/post.handler
Events:
Post: # Invoke on post requests to /todonts
Type: HttpApi
Properties:
Path: /todonts
Method: post
Policies:
- SQSSendMessagePolicy: # Use predefined IAM policy
QueueName:
Fn::GetAtt: [TodontsQueue, QueueName]
ProcessFunction:
Type: AWS::Serverless::Function
Properties:
Handler: src/process.handler
Events: # Consume SQS queue
SQSQueueEvent:
Type: SQS
Properties:
Queue:
Fn::GetAtt: [TodontsQueue, Arn]
Policies: # Use predefined IAM policy
- DynamoDBWritePolicy:
TableName:
Ref: TodontsTable
TodontsTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: sam-todonts-table
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST
TodontsQueue:
Type: AWS::SQS::Queue
Properties:
QueueName: sam-todonts-queue
配置有点冗长,但幸运的是,CLI 可以通过运行sam init
和回答一些有关您计划构建的内容的问题来帮助您开始。
我们可以samconfig.toml
通过运行来生成文件并同时部署sam deploy --guided
。
同样,与无服务器框架 CLI 非常相似,SAM 也预装了多种实用功能,可用于测试和调试您的应用程序。sam local invoke [functionName]
可用于运行 Lambda 函数,或者您可以通过运行 来启动托管函数的本地 HTTP 服务器sam local start-api
。 您还可以通过运行 轻松地从已部署的函数中获取日志sam logs --name [functionName]
。
将应用程序的定义和构建方式分离到两个不同的文件中,其好处在于,template.yml
文件可以非常通用地编写,以便共享和重复使用,只是每个项目中的代码有所不同。SAM 还可以与CodeBuildsamconfig.toml
完美集成,从而实现蓝绿部署。
➕优点
- 支持模板共享和重复使用
- 与 AWS 构建管道完美集成
- 出色的调试和测试实用程序
- 可与CDK结合使用
➖缺点
- 详细配置
- CLI 缺少一些您所期望的功能,例如拆除已部署的应用程序。
资源:
AWS CDK
AWS云开发工具包 (CDK)不仅仅是一个用于创建无服务器应用程序的工具,而是一个成熟的基础设施即代码框架,允许您使用代码(而不是配置)来定义您的应用程序。
您可以通过运行来安装 CDK CLI yarn global add aws-cdk
,然后通过运行 生成一个启动项目cdk init app --language --language typescript
。运行 init 命令时会生成一堆项目配置文件和样板文件,但让我们看看lib/cdk-stack.ts
在文件中描述了我们的 ToDont-app 之后会是什么样子。
// lib/cdk-stack.ts
import * as cdk from '@aws-cdk/core';
import lambda = require('@aws-cdk/aws-lambda-nodejs');
import sqs = require('@aws-cdk/aws-sqs');
import dynamodb = require('@aws-cdk/aws-dynamodb');
import { ApiEventSource, SqsEventSource } from '@aws-cdk/aws-lambda-event-sources';
import { Runtime } from '@aws-cdk/aws-lambda';
export class CdkStack extends cdk.Stack {
constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// define our DynamoDB table
const dynamoTable = new dynamodb.Table(this, 'cdk-todonts-table', {
tableName: 'cdk-todonts-table',
partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
});
// define our SQS buffer queue
const sqsBuffer = new sqs.Queue(this, 'cdk-todonts-queue', {
queueName: 'cdk-todonts-queue',
});
// define our processing lambda
const processLambda = new lambda.NodejsFunction(this, 'cdk-todonts-process', {
runtime: Runtime.NODEJS_14_X,
handler: 'handler',
entry: 'src/process.js',
events: [new SqsEventSource(sqsBuffer)],
environment: {
TABLE_NAME: dynamoTable.tableName
}
});
// grant write access for the processing lambda to our dynamo table
dynamoTable.grantWriteData(processLambda);
// define the lambda backing our API
const postLambda = new lambda.NodejsFunction(this, 'cdk-todonts-post', {
runtime: Runtime.NODEJS_14_X,
entry: 'src/post.js',
handler: 'handler',
events: [new ApiEventSource('POST', '/todonts')],
environment: {
QUEUE_URL: sqsBuffer.queueUrl,
}
});
// grant write access to the SQS buffer queue for our API lambda
sqsBuffer.grantSendMessages(postLambda);
}
}
CDK 应用的基本构建块称为“构造”,它代表一个“云组件”,可以是单个服务实例(例如 SQS 队列),也可以是封装在组件中的一组服务。这些构造可以在项目之间共享和重用,并且我们有一个优秀的社区,构建了大量高质量的组件供您使用。通过代码完整描述应用及其基础架构,我们还可以根据我们的设置编写实际测试——这很酷吧?
在部署第一个应用之前,我们需要引导 AWS 环境(账户和区域组合),以配置 CDK 用于部署应用的一些资源。之后,我们就可以运行cdk deploy
并部署我们的应用程序了。
CDK CLI 在测试和调试方面不如 SAM 和 Serverless 那样实用,但可以将SAM CLI 与 CDK 结合使用,以弥补两者之间的差距。此外,还有一个新成员Serverless-Stack,它是 CDK 的扩展,提供了许多测试实用程序和无服务器专用结构。
➕优点
- 支持组件共享和重用
- 大型且乐于助人的社区
- 使基础设施可测试
- 您可以(可能)使用与实际应用程序相同的编程语言来定义应用程序的基础结构
➖缺点
- 如果想要调用或打印已部署函数的日志,则需要使用其他工具,例如 SAM 或 AWS CLI。
资源:
总结
目前,这个领域正在发生很多变化,虽然我认为这三个框架是目前最突出的,但也出现了各种各样的替代方案。每个框架都有自己的优势和优点,在选择最适合你的项目的解决方案时,几乎没有对错之分。
请在评论中告诉我您最喜欢哪一个以及为什么!
如果您喜欢这篇文章并希望了解更多,请在 Twitter 上关注我@TastefulElk,我经常在那里撰写有关无服务器技术、AWS 和开发人员生产力的文章!
鏂囩珷鏉ユ簮锛�https://dev.to/tastefulelk/serverless-framework-vs-sam-vs-aws-cdk-1g9g