You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在CloudFormation中创建可重用块?解决Lambda重复部署问题

摆脱CloudFormation重复代码:可重用Lambda+API Gateway部署方案

作为刚接触AWS的开发者,这种复制粘贴堆配置的痛苦我太懂了!CloudFormation其实有几个原生特性能帮你彻底解决这个问题,不用再靠复制粘贴维持多实例部署。下面是最适合新手的两种方案,一步步来:

1. 先做一个参数化的基础模板(核心)

首先把你的Lambda+API Gateway组合封装成一个参数化的独立模板,把每个实例不一样的配置抽成参数。比如新建一个base-lambda-api.yaml,内容大概是这样:

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  # 每个实例唯一的标识,用来命名资源
  InstanceName:
    Type: String
    Description: Unique name for this Lambda+API instance
  # Lambda的环境变量,每个实例不同的配置放这
  LambdaEnvVars:
    Type: Map
    Description: Environment variables for the Lambda function
  # API Gateway的路径,比如"/service-a"、"/service-b"
  ApiResourcePath:
    Type: String
    Description: Path for the API Gateway resource
  # Lambda代码的S3位置(如果是打包上传的话,也可以用InlineCode)
  LambdaCodeS3Bucket:
    Type: String
  LambdaCodeS3Key:
    Type: String

Resources:
  # Lambda函数,用参数动态命名和配置
  LambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: !Sub "${InstanceName}-Function"
      Runtime: python3.11 # 换成你的运行时
      Handler: index.lambda_handler # 换成你的handler
      Code:
        S3Bucket: !Ref LambdaCodeS3Bucket
        S3Key: !Ref LambdaCodeS3Key
      Environment:
        Variables: !Ref LambdaEnvVars
      Role: !GetAtt LambdaExecutionRole.Arn

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub "${InstanceName}-ExecutionRole"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole # 基础执行权限,按需添加

  # API Gateway部分,同样用参数动态配置路径
  ApiGatewayRestApi:
    Type: AWS::ApiGateway::RestApi
    Properties:
      Name: !Sub "${InstanceName}-API"

  ApiGatewayResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      ParentId: !GetAtt ApiGatewayRestApi.RootResourceId
      PathPart: !Ref ApiResourcePath
      RestApiId: !Ref ApiGatewayRestApi

  ApiGatewayMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      HttpMethod: POST # 换成你的HTTP方法
      ResourceId: !Ref ApiGatewayResource
      RestApiId: !Ref ApiGatewayRestApi
      AuthorizationType: NONE # 按需改认证方式
      Integration:
        Type: AWS_PROXY
        IntegrationHttpMethod: POST
        Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaFunction.Arn}/invocations"

  ApiGatewayDeployment:
    Type: AWS::ApiGateway::Deployment
    DependsOn: ApiGatewayMethod
    Properties:
      RestApiId: !Ref ApiGatewayRestApi
      StageName: prod # 换成你的阶段名

  # Lambda权限:允许API Gateway调用Lambda
  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref LambdaFunction
      Action: lambda:InvokeFunction
      Principal: apigateway.amazonaws.com
      SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayRestApi}/${ApiGatewayDeployment.StageName}/*/${ApiResourcePath}"

这个模板把所有可变的部分都做成了参数,每个实例只需要传入不同的参数值就行,不用改资源定义。

2. 在主模板中用嵌套栈(Nested Stacks)重用

接下来在你的主CloudFormation模板里,通过AWS::CloudFormation::Stack资源来引用上面的基础模板,每个实例对应一个嵌套栈,传入不同的参数。比如主模板main-stack.yaml:

AWSTemplateFormatVersion: '2010-09-09'
Parameters:
  # 可以把公共的参数抽出来,比如代码桶的名字
  CommonLambdaCodeS3Bucket:
    Type: String
    Description: S3 bucket holding Lambda code

Resources:
  # 第一个实例:Service A
  ServiceAStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./base-lambda-api.yaml # 如果是上传到S3的话,换成S3的URL
      Parameters:
        InstanceName: ServiceA
        LambdaEnvVars:
          CONFIG_KEY: service-a-value
          ANOTHER_CONFIG: foo
        ApiResourcePath: service-a
        LambdaCodeS3Bucket: !Ref CommonLambdaCodeS3Bucket
        LambdaCodeS3Key: lambda-code.zip # 你的代码包路径

  # 第二个实例:Service B
  ServiceBStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: ./base-lambda-api.yaml
      Parameters:
        InstanceName: ServiceB
        LambdaEnvVars:
          CONFIG_KEY: service-b-value
          ANOTHER_CONFIG: bar
        ApiResourcePath: service-b
        LambdaCodeS3Bucket: !Ref CommonLambdaCodeS3Bucket
        LambdaCodeS3Key: lambda-code.zip

这样你要新增多少个实例,就在主模板里加一个ServiceXStack资源就行,完全不用复制粘贴Lambda和API的配置代码,只需要改参数!

进阶方案:CloudFormation模块(Modules)

如果你想更灵活的封装(比如支持更多自定义选项,或者跨模板共享),可以试试CloudFormation的模块(Modules)。模块是比嵌套栈更轻量的可重用组件,你可以把Lambda+API的组合做成一个模块,然后在模板里用AWS::CloudFormation::ModuleVersion引用,用法和嵌套栈类似,但更适合复杂的可重用场景。不过对于新手来说,嵌套栈已经足够解决你的问题,模块可以等你熟悉后再尝试。

注意事项

  • 如果你的Lambda代码是内联的(InlineCode),也可以把代码内容做成参数,但更推荐把代码打包上传到S3,这样基础模板更干净。
  • 嵌套栈的模板URL如果是本地文件,在部署的时候需要用aws cloudformation package命令把本地模板上传到S3,或者直接把基础模板上传到S3后用S3 URL。
  • 权限方面,确保部署CloudFormation的角色有创建嵌套栈、Lambda、API Gateway等资源的权限。

内容的提问来源于stack exchange,提问作者Rohan Büchner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:10:35