如何在 AWS Cloud Formation 中实施嵌套堆栈?
Posted
技术标签:
【中文标题】如何在 AWS Cloud Formation 中实施嵌套堆栈?【英文标题】:How do I implement Nested Stacks in AWS Cloud formation? 【发布时间】:2021-10-26 14:02:09 【问题描述】:我正在开发一个 AWS Lambda 应用程序。这是一个 REST API,所以我使用的是 AWS Lambda、API Gateway 和 AWS RDS。我正在使用 aws sam
进行部署和所有操作。
我的 REST API 中有 193 个端点,这意味着 193 个 Lambda 函数。当我尝试部署它时,我收到以下错误消息。
Waiting for changeset to be created..
Error: Failed to create changeset for the stack: aaa-restapi, ex: Waiter ChangeSetCreateComplete failed:
Waiter encountered a terminal failure state: For expression "Status" we matched expected path:
"FAILED" Status: FAILED. Reason: Template format error:
Number of resources, 583, is greater than maximum allowed, 500
下面是我template.yaml
的一小部分。 请注意,在下面的代码中,我唯一要删除的是 100 多个 Lambda 函数。所有 Lambda 函数看起来都一样,除了它们为 REST API 打开的端点外没有区别。其他一切都在那里。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
Globals:
Function:
Timeout: 30
VpcConfig:
SecurityGroupIds:
- sg-041f2459xxx921e8e
SubnetIds:
- subnet-03xxdb2d
- subnet-c4dxx4cb
- subnet-af5xxx8
- subnet-748xxf28
- subnet-d13xxx9c
- subnet-e9exxxx7
Resources:
GetAllAccountingTypesFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-getall.getallaccountingtypes
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api
Properties:
Path: /accountingtypes/getall
Method: get
GetAccountingTypeByIDFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-byid.getbyid
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api
Properties:
Path: /accountingtypes/getbyid
Method: get
GetUserRoleByIDFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyid.getUserRoleByID
Runtime: nodejs14.x
Events:
GetUserRoleByIDAPIEvent:
Type: Api
Properties:
Path: /userrole/getbyid
Method: get
GetUserRoleByUserFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyuser.getUserRoleByUser
Runtime: nodejs14.x
Events:
GetUserRoleByUserAPIEvent:
Type: Api
Properties:
Path: /userrole/getbyuser
Method: get
GetUserRoleByRoleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyrole.getAllUsersByRole
Runtime: nodejs14.x
Events:
GetUserRoleByRoleAPIEvent:
Type: Api
Properties:
Path: /userrole/getbyrole
Method: get
SaveUserRoleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-save.saveUserRole
Runtime: nodejs14.x
Events:
SaveUserRoleAPIEvent:
Type: Api
Properties:
Path: /userrole/save
Method: post
UpdateUserRoleFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-update.updateeUserRole
Runtime: nodejs14.x
Events:
UpdateUserRoleAPIEvent:
Type: Api
Properties:
Path: /userrole/update
Method: post
LambdaRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ec2:DescribeNetworkInterfaces
- ec2:CreateNetworkInterface
- ec2:DeleteNetworkInterface
- ec2:DescribeInstances
- ec2:AttachNetworkInterface
Resource: '*'
Outputs:
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for functions"
Value: !Sub "https://$ServerlessRestApi.execute-api.$AWS::Region.amazonaws.com/Prod/"
我查看了互联网并发现我需要做嵌套堆栈。在我看过的所有教程中,他们都在谈论将你的堆栈划分为安全、网络、管理等等。我不需要它们中的任何一个,这是一个简单的 REST API,我所需要的只是在不遇到 AWS 限制错误的情况下部署它。
我不明白如何用我的代码实现嵌套堆栈。以我上面的代码为例,有人可以告诉我如何实现嵌套堆栈吗?然后我可以查看代码,从中学习并将其实现到完整的应用程序中。
----更新-------
按照罗伯特的建议,我设法制作了嵌套堆栈。然而我们有一个问题。它为每个堆栈创建了不同的 API Gateway URL。但我只想要一个 API 网关 URL。下面是我的代码。
template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-041f2459dcd921e8e
SubnetIds:
- subnet-0381db2d
- subnet-c4d5c4cb
- subnet-af5c03c8
- subnet-7487df28
- subnet-d139d69c
- subnet-e9e88bd7
Resources:
GetAllAccountingTypesFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-getall.getallaccountingtypes
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /accountingtypes/getall
Method: get
GetAccountingTypeByIDFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/accounting-types/accountingtypes-byid.getbyid
Runtime: nodejs14.x
Events:
GetAllAccountingTypesAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /accountingtypes/getbyid
Method: get
# DependsOn: GetAllAccountingTypesFunction
NestedStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: template_user.yaml
LambdaRole:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
Path: /
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: root
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- ec2:DescribeNetworkInterfaces
- ec2:CreateNetworkInterface
- ec2:DeleteNetworkInterface
- ec2:DescribeInstances
- ec2:AttachNetworkInterface
Resource: '*'
Outputs:
# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function
# Find out more about other implicit resources you can reference within SAM
# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api
HelloWorldApi:
Description: "API Gateway endpoint URL for Prod stage for functions"
Value: !Sub "https://$ServerlessRestApi.execute-api.$AWS::Region.amazonaws.com/Prod/"
template_user.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
aws-restapi
Sample SAM Template for aws-restapi
Globals:
Function:
Timeout: 5
VpcConfig:
SecurityGroupIds:
- sg-041f2****cd921e8e
SubnetIds:
- subnet-03***b2d
- subnet-c4d***cb
- subnet-af5***8
- subnet-74***f28
- subnet-d139***c
- subnet-e9***bd7
Resources:
GetUserRoleByIDFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyid.getUserRoleByID
Runtime: nodejs14.x
Events:
GetUserRoleByIDAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/getbyid
Method: get
GetUserRoleByUserFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyuser.getUserRoleByUser
Runtime: nodejs14.x
Events:
GetUserRoleByUserAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/getbyuser
Method: get
# DependsOn: GetUserRoleByIDFunction
GetUserRoleByRoleFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-getbyrole.getAllUsersByRole
Runtime: nodejs14.x
Events:
GetUserRoleByRoleAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/getbyrole
Method: get
#DependsOn: GetUserRoleByUserFunction
SaveUserRoleFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-save.saveUserRole
Runtime: nodejs14.x
Events:
SaveUserRoleAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/save
Method: post
# DependsOn: GetUserRoleByRoleFunction
UpdateUserRoleFunction:
Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction
Properties:
CodeUri: aws-restapi/
Handler: source/user-role/userrole-update.updateeUserRole
Runtime: nodejs14.x
Events:
UpdateUserRoleAPIEvent:
Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api
Properties:
Path: /userrole/update
Method: post
#DependsOn: SaveUserRoleFunction
在此示例中,我有两个堆栈,API Gateway 确实创建了 2 个 URL。
template.yaml
URL - https://ez5khz***.execute-api.us-east-1.amazonaws.com/Prod/
template_user.yaml
URL - https://7imy9b6***.execute-api.us-east-1.amazonaws.com/Prod/
我希望将使用 template.yaml
创建的 URL 应用于所有 lambda 函数,无论它位于哪个嵌套堆栈中。我还计划稍后为其分配一个域。
我怎样才能让它在一个 URL 下工作?
【问题讨论】:
【参考方案1】:您可以使用Cloudformation Stack Resource 在 CloudFormation 中实现嵌套堆栈。模板 url 将使用 Cloudformation Package command 解析。
代码示例:
NestedStack:
Type: AWS::CloudFormation::Stack
Properties:
TemplateURL: ./src/nested-stack/infrastructure.yml
编辑:也许您应该将一些端点合并到一个 Lambda 中,并使用 express 之类的东西进行路由。
【讨论】:
我认识罗伯特。我对该链接有很多看法。但我更需要一个与我类似的代码示例,因为我不明白如何使链接内容为我工作。 好的,这将我的 lambda 函数拆分为多个堆栈,对吗?你能用你的代码示例替换我的代码,并告诉我这些 lambda 函数将如何分成不同的堆栈吗?关于您的建议,不,我不想使用 express 或任何只会增加不必要的复杂性的东西。 您需要将我的 sn-p 添加到您的 .yml 文件中,然后创建一个新的 .yml 文件,在其中放置一些 Lambda。我的 sn-p 的 Template Url 需要指向您的第二个 .yml 文件。 啊!我们去吧。让我试试看。 谢谢罗伯特,它成功了。但现在它为它创建的每个堆栈创建不同的 API 网关端点。我已经更新了我的问题,请检查并提出建议。以上是关于如何在 AWS Cloud Formation 中实施嵌套堆栈?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Cloud Formation 模板自动扩展 DynamoDB?
我能否在 SAM 模板中使用 AWS Cloud Formation 资源语法,反之亦然?
AWS Cloud Formation 陷入 Review_In_Progress
AWS Cloud Formation !Sub & !Ref AWS::Serverless::Function Policies 中的函数