ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Serverless Framework AWS 基础设施资源(resources)指南:CloudFormation 集成、资源命名规范与 extensions 覆盖机制

Serverless Framework AWS 基础设施资源(resources)指南:CloudFormation 集成、资源命名规范与 extensions 覆盖机制 Serverless Framework AWS 基础设施资源resources指南CloudFormation 集成、资源命名规范与 extensions 覆盖机制【免费下载链接】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本文面向使用 AWS Provider 的 Serverless Framework 开发者系统讲解如何在serverless.yml的resources属性中声明 DynamoDB、S3 等基础云资源、框架如何把资源并入每次部署创建的 CloudFormation 栈、框架自动生成资源的命名规律以及如何通过resources.extensions精准覆盖框架生成的资源而不会造成意外冲突。读完本文你将能够独立编写基础设施资源的声明式配置、预测并引用框架生成的资源逻辑名并安全地定制诸如日志保留期限之类的资源属性。本文对应的仓库文档位于 resources.md。什么是 AWS 基础设施资源在 Serverless Framework 的语境中当使用 AWS 作为 Service 的 Provider 时Resources资源指的是服务中的 AWS Lambda 函数所依赖的那些“其他 AWS 基础设施资源”例如 AWS DynamoDB 表、AWS S3 存储桶、SNS 主题、SQS 队列等。与之相对Service则是把函数、事件与资源组织在一起的部署单元。使用 Serverless Framework你可以在serverless.yml中直接定义所需的基础设施资源并随服务一并部署不必单独维护一套 CloudFormation 工程也不必到 AWS 控制台逐个创建资源。这是框架“基础设施即代码”能力在 AWS Provider 下的核心体现。在 serverless.yml 中声明基础设施资源每个 Stage 对应一个 CloudFormation 栈框架的工作模型很简洁你用serverless.yml向每个 Stage 部署的内容最终都是一个独立的 AWS CloudFormation 栈。你的 Lambda 函数及其事件配置被定义并部署在这个栈中。当你在配置中加入resources后这些资源会在执行serverless deploy时被一并加入同一个 CloudFormation 栈。resources属性的语法在serverless.yml中定义 AWS 资源只需使用名为resources的属性。该属性的内容是原始的 CloudFormation 模板语法YAML 形式例如下面的配置创建了一张 DynamoDB 用户表# serverless.yml service: usersCrud provider: aws functions: resources: # CloudFormation template syntax Resources: usersTable: Type: AWS::DynamoDB::Table Properties: TableName: usersTable AttributeDefinitions: - AttributeName: email AttributeType: S KeySchema: - AttributeName: email KeyType: HASH ProvisionedThroughput: ReadCapacityUnits: 1 WriteCapacityUnits: 1可以看到resources的结构与 CloudFormation 模板完全对应Resources内定义资源逻辑名、Type为 AWS 资源类型、Properties为该类型的属性。任何种类的资源Resources、Outputs等都可以挂接到你的 CloudFormation 栈中。对于敏感数据或需要复用的配置你还可以在这些资源模板中使用 Serverless Variables例如${env:DB_PASSWORD}、${self:custom.someValue}、${cf:other-stack.OutputKey}等变量表达式在打包阶段被解析为最终值。两个重要注意事项不要覆盖框架自动生成的资源。如果把资源直接放在resources.Resources下且其逻辑名恰好与框架自动生成的某个资源同名你可能会“意外覆盖”框架生成的资源导致框架内部对该资源的引用如函数权限、事件源绑定中的Ref指向你自定义的版本而行为错乱。如果你确实希望有意图地扩展框架生成的资源例如给日志组加保留期、给部署桶加标签请使用resources.extensions小节详见下文 使用 resources.extensions 覆盖框架生成的资源。用null赋值移除资源属性。由于 CloudFormation 本身不允许属性值为null框架会在上传最终模板前把属性值为null的属性从模板中剥离。因此你可以利用这一点“关闭”某个由框架生成、但你又不需要的属性。仓库中对应实现位于 strip-null-props-from-template-resources.js它遍历最终模板的资源属性对null值直接剔除见该文件的属性判空逻辑属于package阶段对模板的预处理步骤。框架生成资源的命名规范参考统一命名模式为了让最终部署的 CloudFormation 模板中的资源命名保持一致框架使用如下标准模式{Function Name}{CloudFormation Resource Type}{Resource Name}{SequentialID, instanceId 或 Random String}各组成部分的含义Function Name函数名——可选。仅当某资源希望在函数名变更时被重建时才会带上函数名前缀这类资源也被称为function bound函数绑定资源。CloudFormation Resource Type资源类型——例如 S3 桶对应S3Bucket。Resource Name资源名——针对具体资源的标识例如 S3 桶的桶名。SequentialID, instanceId or Random String序号 / 实例 ID / 随机串——少量资源需要追加可选的顺序号、Serverless 的 instanceId可通过${sls:instanceId}变量访问或一段随机字符串以区分同名实例。所有由 Serverless 部署的资源名都必须遵循上述命名模式唯一的例外出于向后兼容是用于上传部署产物的那个 S3 桶。normalizedName 与路径归一化文中提到的normalizedName规范化名指去掉资源名中不允许出现的字符如特殊字符并符合首字母大写等大小写要求。在源码中这套归一化逻辑集中实现在 naming.jsnormalizeName负责首字母大写第 38-40 行normalizeNameToAlphaNumericOnly进一步将名称清洗为仅保留字母数字第 41-43 行normalizePathPart则处理路径段——把-替换为Dash、把形如{xxx}的路径参数替换为xxxVar并去除其余非法字符第 47-54 行。对应的单元测试见 naming.test.js。如果你的 URL 中存在路径参数它们同样会被归一化并且隐式地追加一个Var。例如POST /users/{user_id}这个路径对应的normalizedPath会被归一化为UsersUseridVarTestPost。小技巧用 serverless package 反查资源名如果你不确定想要在自己的自定义资源中引用的某个框架资源到底叫什么名字可以执行一次serverless package该命令会为你的 Service 生成 CloudFormation 模板输出在.serverless文件夹下文件名为cloudformation-template-update-stack.json。打开该文件即可查到框架生成资源的确切逻辑名。这个文件名在源码中同样有据可查naming.js的getCompiledTemplateFileName()返回的正是cloudformation-template-update-stack.json第 93-95 行。各类资源的命名模板与示例下表汇总了框架自动生成的各类 AWS 资源的命名模板与具体示例便于你在自定义资源或resources.extensions中准确引用AWS 资源类型命名模板示例S3::BucketS3Bucket{normalizedBucketName}S3BucketMybucketIAM::RoleIamRoleLambdaExecutionIamRoleLambdaExecutionLambda::Function{normalizedFunctionName}LambdaFunctionHelloLambdaFunctionLambda::Url{normalizedFunctionName}LambdaFunctionUrlHelloLambdaFunctionUrlLambda::Version{normalizedFunctionName}LambdaVersion{sha256}HelloLambdaVersionr3pgoTvv1xT4E4NiCL6JG02fl6vIyi7OS1aW0FwAILogs::LogGroup{normalizedFunctionName}LogGroupHelloLogGroupLambda::Permission按事件源区分Schedule 为{normalizedFunctionName}LambdaPermissionEventsRuleSchedule{index}CloudWatch Event 为{normalizedFunctionName}LambdaPermissionEventsRuleCloudWatchEvent{index}CloudWatch Log 为{normalizedFunctionName}LambdaPermissionLogsSubscriptionFilterCloudWatchLog{index}IoT 为{normalizedFunctionName}LambdaPermissionIotTopicRule{index}S3 为{normalizedFunctionName}LambdaPermission{normalizedBucketName}S3APIG 为{normalizedFunctionName}LambdaPermissionApiGatewaySNS 为{normalizedFunctionName}LambdaPermission{normalizedTopicName}SNSAlexa Skill 为{normalizedFunctionName}LambdaPermissionAlexaSkillAlexa Smart Home 为{normalizedFunctionName}LambdaPermissionAlexaSmartHome{index}Cognito User Pool Trigger Source 为{normalizedFunctionName}LambdaPermissionCognitoUserPool{normalizedPoolId}TriggerSource{triggerSource}Schedule 示例HelloLambdaPermissionEventsRuleSchedule1CloudWatch Event 示例HelloLambdaPermissionEventsRuleCloudWatchEvent1CloudWatch Log 示例HelloLambdaPermissionLogsSubscriptionFilterCloudWatchLog1IoT 示例HelloLambdaPermissionIotTopicRule1S3 示例HelloLambdaPermissionBucketS3APIG 示例HelloLambdaPermissionApiGatewaySNS 示例HelloLambdaPermissionTopicSNSAlexa Skill 示例HelloLambdaPermissionAlexaSkillAlexa Smart Home 示例HelloLambdaPermissionAlexaSmartHome1Cognito 示例HelloLambdaPermissionCognitoUserPoolMyPoolTriggerSourceCustomMessageEvents::RuleSchedule 为{normalizedFunctionName}EventsRuleSchedule{SequentialID}CloudWatch Event 为{normalizedFunctionName}EventsRuleCloudWatchEvent{SequentialID}Schedule 示例HelloEventsRuleSchedule1CloudWatch Event 示例HelloEventsRuleCloudWatchEvent1AWS::Logs::SubscriptionFilter{normalizedFunctionName}LogsSubscriptionFilterCloudWatchLog{SequentialID}HelloLogsSubscriptionFilterCloudWatchLog1AWS::IoT::TopicRule{normalizedFunctionName}IotTopicRule{SequentialID}HelloIotTopicRule1ApiGateway::RestApiApiGatewayRestApiApiGatewayRestApiApiGateway::ResourceApiGatewayResource{normalizedPath}ApiGatewayResourceUsersApiGateway::MethodApiGatewayMethod{normalizedPath}{normalizedMethod}ApiGatewayMethodUsersGetApiGateway::Authorizer{normalizedFunctionName}ApiGatewayAuthorizerHelloApiGatewayAuthorizerApiGateway::DeploymentApiGatewayDeployment{instanceId}ApiGatewayDeployment12356789ApiGateway::ApiKeyApiGatewayApiKey{OptionalNormalizedName}{SequentialID}ApiGatewayApiKeyFree1ApiGateway::UsagePlanApiGatewayUsagePlan{OptionalNormalizedName}ApiGatewayUsagePlanFreeApiGateway::UsagePlanKeyApiGatewayUsagePlanKey{OptionalNormalizedName}{SequentialID}ApiGatewayUsagePlanKeyFree1ApiGateway::StageApiGatewayStageApiGatewayStageSNS::TopicSNSTopic{normalizedTopicName}SNSTopicSometopicSNS::Subscription{normalizedFunctionName}SnsSubscription{normalizedTopicName}HelloSnsSubscriptionSomeTopicAWS::Lambda::EventSourceMappingDynamoDB 为{normalizedFunctionName}EventSourceMappingDynamodb{tableName}Kinesis 为{normalizedFunctionName}EventSourceMappingKinesis{streamName}DynamoDB 示例HelloLambdaEventSourceMappingDynamodbUsersKinesis 示例HelloLambdaEventSourceMappingKinesisMystreamCognito::UserPoolCognitoUserPool{normalizedPoolId}CognitoUserPoolPoolId使用 resources.extensions 覆盖框架生成的资源为什么需要 extensions框架生成的资源日志组、IAM 角色、API 网关等虽然开箱即用但某些属性框架默认并不开放配置入口例如日志组的保留天数RetentionInDays。此时既不能直接在resources.Resources下新建同名资源去覆盖会产生上文所述的意外覆盖风险也不能放任不管。正确做法是把所有这类扩展统一放在resources.extensions小节并以上表命名模板中的逻辑名作为键。以“把某个函数日志组的保留时间设置为 30 天”为例functions: write-post: handler: handler.writePost events: - httpApi: POST /api/posts/new resources: extensions: WriteDashPostLogGroup: Properties: RetentionInDays: 30这里需要注意两点它们都围绕normalizedFunctionName的写法逻辑名必须以大写字母开头函数名中的-会被改为Dash、_会被改为Underscore。因此函数write-post的日志组逻辑名由{normalizedFunctionName}LogGroup推导为WriteDashPostLogGroupwrite-post→ 大写首字母Write-→Dash示例即按此规则编写。这也印证了命名规则与源码naming.js中normalizePathPart、normalizeName等函数所体现的归一化约定。extensions 的合并语义resources.extensions中每个资源对象的各个属性与框架生成的原资源属性遵循如下合并规则资源属性合并操作Condition若存在扩展值则直接设置为其值CreationPolicy若存在扩展值则直接设置为其值DeletionPolicy若存在扩展值则直接设置为其值DependsOn合并。扩展值会被追加到原资源的DependsOn列表Metadata合并。若原资源中存在同名 Metadata 键其值会被扩展值替换Properties合并。若原资源中存在同名属性其值会被扩展值替换UpdatePolicy若存在扩展值则直接设置为其值UpdateReplacePolicy若存在扩展值则直接设置为其值其他属性不支持。若尝试扩展不支持的属性框架会抛出错误从表格可见扩展的语义是“覆盖 白名单”Properties、Metadata采用键级合并同名覆盖、异名保留DependsOn采用追加式合并而Condition、DeletionPolicy等整块属性采用整体替换一旦试图扩展白名单之外的属性配置校验即失败并报错。使用边界需要注意通过resources.extensions进行扩展仅作用于 CloudFormation 模板的Resources部分即资源定义对Outputs、Conditions等其他顶层段落无效。结合源码看 resources 的部署链路为了便于你在仓库中继续深入这里把与resources机制直接相关的实现位置整理如下命名规范的核心工具类naming.js——getStackName()把栈名定为{service}-{stage}第 61-71 行确认了“一个 Stage 一个栈”的模型其余如getRoleName、getLogGroupName等同文件内的命名方法共同实现了上文的命名模板。命名规范单元测试naming.test.js——覆盖各类资源逻辑名的生成断言是查询“某个名字到底怎么拼”的最直接依据。空属性清理strip-null-props-from-template-resources.js——上传前剥离值为null的属性支撑“用 null 移除属性”的用法。打包阶段模板加工目录package/lib 下集中了核心模板生成generate-core-template.js、core-cloudformation-template.json、iam-role-lambda-execution-template.json、自定义 provider 资源合并merge-custom-provider-resources.js、函数日志组function-log-groups.js等逻辑从源码结构看你写在serverless.yml中的resources片段会在package阶段被合并进最终 CloudFormation 模板随后才进入deploy阶段由 CloudFormation 建栈。若想跟踪“模板最终长什么样”除了文档推荐的serverless package也可以在这些编译模块中检索Resources的组装点。总结在 AWS Provider 下resources是 Serverless Framework 把“业务函数”与“基础设施”统一管理的桥梁它以原生 CloudFormation 语法直通 AWS 全部资源类型把基础设施变更纳入同一套部署与回滚流程。用好它的关键有三点正确书写在resources下使用标准 CloudFormation YAML 定义资源必要时结合 Serverless Variables 注入环境相关取值并用null精简不需要的默认属性。掌握命名通过 本文的命名表 和serverless package产物反查框架生成的逻辑名避免凭感觉引用。安全定制凡是想调整框架生成资源一律走resources.extensions白名单式合并避开直接覆盖带来的资源竞争与引用错乱。其他相关概念Service 与函数如何定义、IAM 权限如何配置、Lambda Layer 的发布方式等可继续阅读同目录下的 intro.md、functions.md、iam.md 与 layers.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),仅供参考
返回列表