Serverless Framework 核心概念指南:在 AWS 上用 Functions、Events、Resources 与 Services 构建事件驱动架构
2026/9/10 21:19:22 网站建设 项目流程

Serverless Framework 核心概念指南:在 AWS 上用 Functions、Events、Resources 与 Services 构建事件驱动架构

【免费下载链接】serverless⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.项目地址: https://gitcode.com/GitHub_Trending/se/serverless

Serverless Framework 是一套开源的 CLI 工具,帮助开发者在 AWS 上开发并部署 AWS Lambda 函数及其所需的 AWS 基础设施资源。它以开箱即用的"结构化、自动化与最佳实践",让你把精力集中在构建由Functions(函数)Events(事件)组合而成的复杂事件驱动无服务器架构上。阅读本篇后,你将掌握 Serverless Framework 的四大核心概念(Functions、Events、Resources、Services)及其在serverless.yml中的声明方式,并了解从服务配置、多语言支持、资源命名到插件扩展的完整知识链路。

本文内容以仓库中的官方概念文档 docs/sf/providers/aws/guide/intro.md 为骨架,并结合 functions.md、events.md、resources.md、services.md 及各页面背后的核心源码进行纵深展开。

Serverless Framework 为何与众不同

在进入具体概念之前,先理解 Framework 与"普通应用框架"的本质区别,这决定了你理解后续所有概念的方式:

  • 它同时管理"代码"与"基础设施":一份serverless.yml既可以声明 Lambda 业务代码,也可以声明背后的 DynamoDB 表、S3 桶、SNS Topic 等云资源;
  • 它支持多种语言:Node.js、Python、Java 等运行时均可部署,框架本身与语言无关;
  • 它以事件驱动为核心抽象:函数只负责"单件事务",由事件触发、由框架自动创建配套基础设施并完成监听配置。

以下四个概念是理解 Serverless Framework 的地基:Functions(代码单元)、Events(触发来源)、Resources(被函数使用的基础设施)以及把它们编排到一起的 Services(组织单元)。

Functions:部署在云上的独立执行单元

Functions是无服务器应用的代码载体,它们被部署到 AWS Lambda 中执行。每个函数都是一个独立的"执行与部署单元",形态上类似于一个微服务。一个函数本质上只是一段"部署到云端的代码",通常被写成只完成单一任务,例如:

  • 将用户保存到数据库;
  • 处理数据库中的某个文件;
  • 执行一个定时任务。

在 functions.md 中有完整的函数配置说明,这里先给一个典型的函数声明形态:

# serverless.yml service: myService provider: name: aws runtime: nodejs14.x runtimeManagement: auto # 可选,默认 auto,可设 'auto' 或 'onFunctionUpdate' memorySize: 512 # 可选,单位 MB,默认 1024 timeout: 10 # 可选,单位秒,默认 6 functions: hello: handler: handler.hello # 必填,指向函数代码模块 name: ${sls:stage}-lambdaName # 可选,部署后的 Lambda 名称 description: Description of what the lambda function does # 可选 runtime: python3.11 # 可选,覆盖 provider 级运行时 memorySize: 512 # 可选,单位 MB,默认 1024 timeout: 10 # 可选,单位秒,默认 6 provisionedConcurrency: alias: active # 可选,默认 "provisioned" executions: 3 # 指定为对象时必填 reservedConcurrency: 5 # 可选,默认遵循账户并发上限

这里的handler属性指向包含待执行代码的"文件与模块":

// handler.js module.exports.functionOne = function (event, context, callback) {}

一个服务内可以声明任意多个函数,且函数属性遵循"provider 级继承 + 函数级覆盖"的分层规则。例如在 provider 层设置memorySize: 512,所有函数都会继承;若某函数需要更大的内存,再在函数级单独覆盖。这一继承-覆盖规则同样适用于环境变量、标签、VPC、追踪等几乎所有配置维度(详见 functions.md)。

此外,functions也可以声明为一个数组并借助变量加载把不同函数拆分到多个文件,便于按业务模块组织(例如${file(./foo-functions.yml)})。

Events:触发函数运行的"引信"

Events是触发函数运行的信号源。在使用 AWS 作为 provider 时,服务中定义的events可以是任何能触发 AWS Lambda 的 AWS 资源,例如:

  • API Gateway URL 上的 HTTP 请求(例如 REST API);
  • S3 桶中新上传的文件(例如图片上传场景);
  • CloudWatch 定时调度(例如每 5 分钟执行一次);
  • SNS Topic 中的一条消息;
  • CloudWatch 告警;
  • 以及更多其他事件源。

关键机制:当你在 Lambda 函数上配置一个事件时,Serverless Framework 会自动创建该事件所需的基础设施(例如一个 API Gateway 端点),并把你的函数配置为监听它。也就是说,声明一个事件 = 声明了"基础设施 + 权限 + 触发绑定"整套链路。

事件定义在functions下的events数组里,事件是对象,可携带事件专属信息;数组形态意味着一个函数可被多个事件触发(只要 AWS 支持):

# 'functions' in serverless.yml functions: createUser: # 函数名 handler: handler.users # 指向 handler.js 文件中的 users 导出函数 events: - httpApi: 'POST /users/create' - httpApi: 'PUT /users/update' - httpApi: 'DELETE /users/delete'

HTTP 事件还支持路径参数,只需在路由中声明{id}之类的占位符,即可把路径参数传给 Lambda 函数(更多细节见 docs/sf/providers/aws/events/apigateway.md):

events: - httpApi: 'GET /users/{id}'

Framework 支持 AWS Lambda 的全部事件类型,完整的"事件词典"位于 docs/sf/providers/aws/events/README.md(schedule、S3、SNS、SQS、Kinesis/Streams、EventBridge、IoT、MQ、Kafka/MSK、ALB、WebSocket、Cognito 等)。每种事件都有大量配置与独立功能,本概念指南只负责"事件是什么、如何挂接",具体到某类事件的参数请进入对应页面。

从源码实现看,事件类型的支撑正是 Framework "核心插件集"的一部分——packages/serverless/lib/plugins/index.js 中的loadModules()依次加载了schedule.jss3/index.jsapi-gateway/index.jssns.jsstream.jskafka.jsactivemq.jsrabbitmq.jsmsk/index.jsalb/index.jsalexa-skill.jsalexa-smart-home.jsiot.jscloud-watch-event.jscloud-watch-log.jscognito-user-pool.jsevent-bridge/index.jssqs.jscloud-front.jshttp-api.js等事件编译模块。每个模块都对应一个事件类型的"编译/编排插件",这印证了文档"Serverless Framework 支持所有 AWS Lambda 事件且不止于此"的描述。

Resources:函数依赖的 AWS 基础设施

Resources是函数所使用的 AWS 基础设施组件,例如:

  • DynamoDB 表(用于保存用户/文章/评论等数据);
  • S3 桶(用于保存图片或文件);
  • SNS Topic(用于异步发送消息);
  • 任何可以在 CloudFormation 中定义的东西,Serverless Framework 都支持

Framework 不仅能部署函数与事件,也能部署 AWS 资源。所有使用awsprovider 的服务,在每个阶段(stage)的部署本质上对应一个独立的 AWS CloudFormation 栈——Lambda 函数、事件配置、自定义资源最终都会被打包进这个栈,由 CloudFormation 统一执行创建与更新。

serverless.yml中通过resources属性直接书写"原生的 CloudFormation 模板语法"(YAML):

# serverless.yml service: usersCrud provider: aws functions: resources: # CloudFormation 模板语法 Resources: usersTable: Type: AWS::DynamoDB::Table Properties: TableName: usersTable AttributeDefinitions: - AttributeName: email AttributeType: S KeySchema: - AttributeName: email KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1

资源命名规则:可被引用的稳定约定

为了让生成的 CloudFormation 模板命名一致、可被自定义资源引用,Framework 采用统一命名模式:

{函数名}{CloudFormation 资源类型}{资源名}{SequentialID / instanceId / 随机串}
  • 函数名:可选,用于区分"随函数名变更而重建"的资源(即 function bound 资源);
  • CloudFormation 资源类型:例如S3Bucket
  • 资源名:具体资源的标识,例如 S3 桶的配置名;
  • SequentialID / instanceId / 随机串:部分资源需要追加的序号、${sls:instanceId}或随机串。

路径变量也会被规范化,例如POST /users/{user_id}会被规范为UsersUseridVarTestPost。下表摘录几个最常见资源类型的命名模板(完整表格见 docs/sf/providers/aws/guide/resources.md):

AWS 资源名称模板示例
S3::BucketS3Bucket{normalizedBucketName}S3BucketMybucket
IAM::RoleIamRoleLambdaExecutionIamRoleLambdaExecution
Lambda::Function{normalizedFunctionName}LambdaFunctionHelloLambdaFunction
Logs::LogGroup{normalizedFunctionName}LogGroupHelloLogGroup
ApiGateway::RestApiApiGatewayRestApiApiGatewayRestApi

排查技巧:不确定某个资源最终叫什么名字时,先执行serverless package,它会生成服务的 CloudFormation 模板到.serverless目录(文件名cloudformation-template-update-stack.json),打开即可查到真实生成的资源名。

扩展与覆盖内置资源

resources.Resources中直接书写资源时,需注意可能误覆盖框架生成的同名资源。若想有意地扩展框架生成的资源,应使用resources.extensions。以"把日志组的保留期设为 30 天"为例(函数名write-post规范化为WriteDashPostLogGroup,注意-Dash_Underscore,且必须以大写字母开头):

functions: write-post: handler: handler.writePost events: - httpApi: 'POST /api/posts/new' resources: extensions: WriteDashPostLogGroup: Properties: RetentionInDays: '30'

extensions的合并语义非常明确(详见 resources.md):PropertiesMetadata是"键级替换式合并",DependsOn是追加式合并,Condition/CreationPolicy/DeletionPolicy/UpdatePolicy/UpdateReplacePolicy直接设为扩展值,其他属性类型不支持(会抛错)。同时框架允许用null赋值"删掉"某个资源属性——因为 CloudFormation 本身不允许这样做,Serverless 会在上传前把这些属性从最终模板中剥离。

Services:Framework 的组织单元

Service(即 project)是 Framework 的组织单元。可以把它想成一个"项目文件",而一个应用可以拥有多个 service。Service 通过一份serverless.yml配置函数、事件与要部署的 AWS 资源:

service: users provider: name: aws # 云服务商配置 functions: # 要部署的函数 usersCreate: events: - httpApi: 'POST /users/create' usersDelete: events: - httpApi: 'DELETE /users/delete' plugins: # 要启用的插件 resources: # 额外要部署的 AWS 资源

执行serverless deploy时,配置文件里的所有内容会被一次性整体部署

服务的目录组织

项目早期,通常建议把该应用的所有函数、事件与资源放在一个 service中:

my-service/ # 包含所有函数与基础设施资源 serverless.yml

随着应用增长,可以拆分成多个 service。常见实践是按"工作流"或"数据模型"来划分——把与同一工作流/数据模型相关的函数聚合在一个 service 里(例如独立的users/posts/comments/各含自己的 CRUD 函数与数据库表)。这样划分的合理性在于:相关函数通常共享公共基础设施资源,把它们作为一个整体部署单元,能获得更好的组织性与关注点分离。当需要编排、协同部署多个 service 时,可参考 docs/sf/guides/compose.md(Compose 机制)。新 service 的创建方式是执行serverless命令并跟随 docs/sf/getting-started.md 的引导。

serverless.yml 的职责与完整形态

每个 service 的配置都存放在serverless.yml中,其主要职责是:

  • 声明一个 serverless service;
  • 定义服务将要部署到的云服务商;
  • 定义一个或多个函数;
  • 定义触发每个函数的事件(如 HTTP 请求);
  • 定义要启用的插件;
  • 定义要创建的 AWS 资源集合;
  • events段中的事件在部署时自动创建所需资源;
  • 通过 变量系统 实现灵活配置。

综合前三节概念,一个相对完整的serverless.yml如下:

# serverless.yml service: users provider: name: aws runtime: nodejs14.x stage: dev # 默认阶段,默认为 dev region: us-east-1 # 覆盖默认区域,默认 us-east-1 profile: production # 本服务使用的默认 AWS profile memorySize: 512 # 覆盖默认内存,默认为 1024 functions: usersCreate: # 函数 handler: users.create events: # 触发该函数的事件 - httpApi: 'POST /users/create' usersDelete: # 函数 handler: users.delete events: - httpApi: 'DELETE /users/delete' resources: # 函数使用的"资源",这里放置原生的 AWS CloudFormation Resources: usersTable: Type: AWS::DynamoDB::Table Properties: TableName: usersTable AttributeDefinitions: - AttributeName: email AttributeType: S KeySchema: - AttributeName: email KeyType: HASH BillingMode: PAY_PER_REQUEST

按阶段(stage)差异化配置

stages段允许针对不同部署阶段做差异化配置,包括参数(params)、可观测性开关以及变量解析器(resolvers)声明,并可用default作为未显式声明阶段的兜底。例如为不同阶段配置不同密钥:

# serverless.yml service: billing stages: prod: params: stripe_api_key: ${env:PROD_STRIPE_API_KEY} default: params: stripe_api_key: ${env:DEV_STRIPE_API_KEY} functions: chargeCustomer: handler: billing.charge environment: STRIPE_API_KEY: ${param:stripe_api_key}

框架会依据当前部署阶段自动解析stripe_api_keystages同样可控制 Dashboard 可观测性开关(observability: true/false)、声明terraform/vault等变量解析器,详细说明见 docs/sf/guides/parameters.md 与 docs/sf/guides/variables/hashicorp/terraform.md 等文档。

部署与移除

部署服务时,serverless.yml中所有函数、事件与资源会被翻译为一份 AWS CloudFormation 模板,并作为单一 CloudFormation 栈整体部署。在serverless.yml所在目录执行:

serverless deploy

部署默认针对dev阶段与us-east-1区域,可通过 CLI 选项覆盖:

serverless deploy --stage prod --region us-east-1

从 deploying.md 的"工作原理"可以看出其整体流程:将配置翻译为 CloudFormation 模板 → 首次创建栈时先建一个存放函数代码 zip 的 S3 桶 → 打包函数代码 → 对比上次部署的文件哈希(一致则终止,实现增量跳过)→ 上传 zip → 把 IAM 角色、函数、事件与资源一并写入 CloudFormation 模板执行。需要移除服务时执行serverless remove,它只清理 AWS 侧的栈与相关资源,本地目录保留,方便以后重新部署到其他阶段、区域或 provider。

版本固定(Version Pinning)

Serverless Framework 通常通过npm install -g serverless全局安装。全局安装的缺点是版本无法锁定在项目package.json中——当你升级 Framework 而同事或 CI 未升级时,可能用上新版本专属的配置语法、部署时却仍由旧版本执行。

解决办法是在serverless.yml顶部声明frameworkVersion(语义化版本,支持精确值与范围),每次 CLI 执行前都会校验当前版本是否落在该范围内:

# serverless.yml frameworkVersion: '^3.0.0' # 例:>=3.0.0 且 <4.0.0 service: users provider: name: aws runtime: nodejs14.x

建议在团队中固定到一个精确版本,确保人人(含 CI)环境完全一致。注意:文档示例中的具体版本号仅为演示,请以你实际安装/期望使用的版本为准。

替代的配置格式:JSON / JavaScript / TypeScript

当需要更大灵活性时,服务配置也可以写成 JSON(serverless.json)、JavaScript(serverless.js)或 TypeScript(serverless.ts)。Framework 本身语言无关,但对 Node.js 项目而言,"前后端同一语言"能降低心智负担。使用 JS/TS 时,文件必须以 JS 对象形式导出配置:

'use strict' // serverless.js module.exports = { service: 'users', functions: { usersCreate: { events: [ { httpApi: 'POST /users/create', }, ], }, // ... }, resources: {}, }
// 需要先在项目 package.json 中安装 @types/serverless import type { Serverless } from 'serverless/aws' // serverless.ts const serverlessConfiguration: Serverless = { service: 'users', functions: { usersCreate: { events: [ { httpApi: 'POST /users/create', }, ], }, // ... }, resources: {}, } module.exports = serverlessConfiguration

两点注意:

  • 使用serverless.ts部署时,需将ts-node单独安装为 devDependency;
  • 文档中绝大多数示例以serverless.yml展示,但所有功能对四种格式一视同仁

Plugins:用插件覆盖与扩展框架能力

你可以通过插件覆盖或扩展 Framework 的功能。每个serverless.yml都可以包含plugins:属性并挂载多个插件:

# serverless.yml plugins: - serverless-offline - serverless-secrets

关于插件的更完整介绍(安装、本地插件、加载顺序、自定义插件编写)在 docs/sf/guides/plugins/README.md,这里简述与概念相关的内容:

  • 插件本质:一段自定义 JavaScript 代码,为 Framework 扩展新功能;Framework 本身也由一组"核心插件"组成,因此自定义插件的写法与核心插件完全一致;
  • 按服务安装:插件按 service 维度安装而非全局。可运行serverless plugin install -n 插件名自动安装并在serverless.yml注册,也可手动npm install --save-dev后手工加入plugins段;
  • 插件专属配置:放在custom段,由各插件文档决定需要配置哪些键;
  • 本地加载:路径以./开头时从服务根目录相对加载本地插件,适合单项目专用插件或开发中插件;
  • 加载顺序:Framework 先加载全部核心插件,再按plugins声明顺序依次加载自定义插件(plugin1先于plugin2)。

从实现上印证"Framework 即一组核心插件":在 packages/serverless/lib/plugins/index.js 中可以看到 Framework 把deployinvokeinfologsmetricsremoverollback、AWS provider 及各类事件编译模块全部统一作为模块列表加载;而 packages/serverless/lib/classes/plugin-manager.js 中的loadAllPlugins(servicePlugins)则负责协调"内置插件(bundled)"与"用户外部插件"的加载与覆盖逻辑——例如某服务若在plugins中显式声明了某社区同名插件,框架会跳过内置版本、优先使用社区实现。理解这一点,对排查"为什么我的插件没生效/被覆盖"很有帮助。

从概念到深度配置:Functions 的进阶能力

Functions 作为无服务器应用的执行核心,其配置面远不止handlerruntime。为了让你在理解概念后能直接落地,这里按 functions.md 提炼若干高频且重要的配置维度:

  • 权限(IAM):每个 Lambda 函数都通过一个 IAM Role 获得访问账户内其他 AWS 资源的权限。可通过provider.iam.role.statements批量声明策略语句(支持 DynamoDB/S3 等操作的细粒度授权),也可通过provider.iam.role直接传入一个已存在的角色 ARN(用法与函数级 IAM 见 docs/sf/providers/aws/guide/iam.md)。
  • Function URLurl: true即可为函数直接生成免 API Gateway 的公开 HTTP 端点;对象形式可配置authorizer: aws_iam(IAM 鉴权)、cors(支持 true 全放开或细粒度配置allowedOrigins/allowedMethods/allowCredentials/exposedResponseHeaders/maxAge等,并可用null移除默认项)、以及invokeMode: RESPONSE_STREAM(流式响应,默认BUFFERED)。
  • 容器镜像:通过image属性引用 ECR 镜像(含uri直接引用已有镜像,或provider.ecr.images定义本地 Dockerfile 构建、再以path/file/buildArgs/platform等控制构建;使用imagehandlerruntime不再适用)。框架会在首次部署时为镜像服务自动创建serverless-<service>-<stage>的 ECR 仓库,并在sls remove时随之移除。
  • 指令集架构:默认 x86_64;在 provider 或函数级设置architecture: arm64即可切换到 AWS Graviton2,可能带来更优的价格与性能。
  • VPC:函数级vpc.securityGroupIds+vpc.subnetIds可把函数放入 VPC(支持双栈子网 IPv6 出站ipv6AllowedForDualStack);provider 级可配置后由函数继承,函数级配置以~(null)覆盖为"无 VPC"。注意 VPC 内函数默认失去公网访问能力,访问 S3/DynamoDB 需 VPC Endpoint、访问 Kinesis 等需 NAT Gateway。
  • 环境变量与标签environmenttags均支持 provider 级与函数级"合并 + 同名覆盖"。
  • 版本管理(versionFunctions):默认每次部署都会生成函数版本(可通过:3之类限定符按版本调用)。版本不会被框架自动清理,需借助插件或工具定期剪除旧版本;versionFunctions: false可关闭该行为。
  • 异步调用治理destinations(onSuccess/onFailure 目标:其他函数、EventBridge、SQS 或 SNS)、maximumEventAge(60 秒~6 小时)、maximumRetryAttempts(0~2)。
  • 可观测性与安全tracing(X-Ray 追踪,true/Active/PassThrough)、kmsKeyArn(自定义 KMS 加密环境变量)、snapStart(Java 11/17/21 的启动加速,且不兼容 provisioned concurrency、arm64、EFS 等)、recursiveLoop(递归调用检测,allow/terminate)。
  • 日志治理:框架默认会为 Lambda 创建 LogGroup 以便服务删除时一并清理;可用disableLogslogRetentionInDayslogDataProtectionPolicy以及logs.logGroupClass: infrequent_access(低频访问日志类,约省 50% 摄入成本,但注意该模式下sls logs -f不可用、需用 CloudWatch Logs Insights 读取,且切换与重建存在文档明确警示的边界情形)管理。

概念落地:一个最小可部署的服务

综合上述概念,你最终交付给框架的是一份"声明式契约":函数回答"代码放哪、怎么执行",事件回答"谁来触发",资源回答"背后依赖什么",service 则把它们打包成一个可整体部署的 CloudFormation 栈。要实际体验,可在仓库相应测试目录的 fixture 中查看更多真实示例(例如 packages/sf-core/tests/integration/simple-nodejs/fixture 下的serverless.yml与 handler),或在空目录中执行serverless交互式引导创建第一个服务。

  • 完整函数配置文档:docs/sf/providers/aws/guide/functions.md
  • 事件配置总入口:docs/sf/providers/aws/guide/events.md 与事件清单 docs/sf/providers/aws/events/README.md
  • 资源与 CloudFormation 扩展:docs/sf/providers/aws/guide/resources.md
  • 服务组织与部署:docs/sf/providers/aws/guide/services.md、docs/sf/providers/aws/guide/deploying.md
  • 插件机制:docs/sf/guides/plugins/README.md、docs/sf/guides/plugins/creating-plugins.md

【免费下载链接】serverless⚡ Serverless Framework – Effortlessly build apps that auto-scale, incur zero costs when idle, and require minimal maintenance using AWS Lambda and other managed cloud services.项目地址: https://gitcode.com/GitHub_Trending/se/serverless

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询