如何在 AWS 云形成中实施嵌套堆栈?

How do I implement Nested Stacks in AWS Cloud formation?

我正在开发 AWS Lambda 应用程序。这是一个 REST API,所以我正在使用 AWS Lambda、API 网关和 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/"
    

我上网查了一下,发现我需要做嵌套堆栈。在我看过的所有教程中,他们都在谈论将您的堆栈划分为安全、网络、管理 bla bla bla。我不需要它们中的任何一个,这是一个简单的 REST API,我所需要的只是在不遇到 AWS 限制错误的情况下进行部署..

我不明白如何用我的代码实现嵌套堆栈。以我上面的代码为例,有人可以告诉我如何在其中实现嵌套堆栈吗?然后我可以查看代码,从那里学习并将其实现到完整的应用程序中。

----------------更新--------------------

按照罗伯特的建议,我设法制作了嵌套堆栈。但是我们有一个问题。它为每个堆栈创建了不同的 API 网关 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 网关确实创建了 2 个 URLs。

  1. template.yaml URL - https://ez5khz***.execute-api.us-east-1.amazonaws.com/Prod/
  2. template_user.yaml URL - https://7imy9b6***.execute-api.us-east-1.amazonaws.com/Prod/

我希望用 template.yaml 制作的 URL 应用于所有 lambda 函数,无论它在哪个嵌套堆栈中。我还计划稍后将域分配到这个。

我怎样才能让它在 URL 下工作?

您可以使用 Cloudformation Stack Resource to implement nested Stacks in CloudFormation. The template url will be resolved by using the Cloudformation Package command.

代码示例:

NestedStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./src/nested-stack/infrastructure.yml

编辑:也许您应该将一些端点合并到一个 Lambda 中,并使用类似 express 的路由。