AWS SAM中跨栈Lambda引用API Gateway的问题求解
解决跨栈引用API Gateway触发Lambda的问题
以下是几种基于CloudFormation/SAM原生能力的可行解决方案:
1. 导出API核心参数,手动构建触发关联
CloudFormation不允许直接跨栈引用完整的API Gateway资源,但可以导出其关键属性,在目标栈中手动搭建触发关系:
步骤1:在栈1中输出API Gateway的必要参数
修改栈1的SAM模板,添加Outputs部分导出RestApi ID和部署阶段名称:
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: MyApi: Type: AWS::Serverless::Api Properties: StageName: prod # 其他API配置项 Outputs: MyApiRestApiId: Value: !Ref MyApi Export: Name: MyApi-RestApiId MyApiStageName: Value: !Ref MyApi.Stage Export: Name: MyApi-StageName
步骤2:在栈2中导入参数并配置触发
在栈2的SAM模板里,通过Fn::ImportValue获取栈1的参数,手动创建API资源、方法以及Lambda调用权限:
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Resources: MyLambda: Type: AWS::Serverless::Function Properties: CodeUri: ./src/ Handler: index.handler Runtime: nodejs18.x # 配置Lambda允许API Gateway调用的权限 ApiLambdaPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref MyLambda Action: lambda:InvokeFunction Principal: apigateway.amazonaws.com SourceArn: !Sub "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ImportedRestApiId}/${ImportedStageName}/*" # 关联已存在的API Gateway ImportedRestApi: Type: AWS::ApiGateway::RestApi Properties: RestApiId: !ImportValue MyApi-RestApiId # 新增API路径与Lambda的集成 NewApiResource: Type: AWS::ApiGateway::Resource Properties: ParentId: !GetAtt ImportedRestApi.RootResourceId PathPart: "new-path" RestApiId: !ImportValue MyApi-RestApiId NewApiMethod: Type: AWS::ApiGateway::Method Properties: HttpMethod: POST ResourceId: !Ref NewApiResource RestApiId: !ImportValue MyApi-RestApiId AuthorizationType: NONE Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Sub "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${MyLambda.Arn}/invocations" Parameters: ImportedRestApiId: Type: String Default: !ImportValue MyApi-RestApiId ImportedStageName: Type: String Default: !ImportValue MyApi-StageName
2. 使用嵌套栈统一管理(架构允许时)
如果两个栈关联度较高,可以将栈1作为栈2的嵌套栈,或创建顶层栈同时包含两个子栈,这样就能直接在栈2中引用栈1的API资源,无需跨栈导出导入:
示例顶层栈模板:
AWSTemplateFormatVersion: '2010-09-09' Resources: ApiStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: ./api-stack.yaml # 栈1的模板路径 LambdaStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: ./lambda-stack.yaml # 栈2的模板路径 Parameters: ApiRestApiId: !GetAtt ApiStack.Outputs.MyApiRestApiId ApiStageName: !GetAtt ApiStack.Outputs.MyApiStageName
之后在栈2的模板中通过参数接收值,直接配置Lambda的API触发事件即可。
3. 用CLI/SDK动态配置(自动化场景)
如果需要更灵活的触发逻辑,可以在栈部署完成后,通过AWS CLI调用API完成关联:
# 获取栈1输出参数 REST_API_ID=$(aws cloudformation describe-stacks --stack-name api-stack --query "Stacks[0].Outputs[?OutputKey=='MyApiRestApiId'].OutputValue" --output text) STAGE_NAME=$(aws cloudformation describe-stacks --stack-name api-stack --query "Stacks[0].Outputs[?OutputKey=='MyApiStageName'].OutputValue" --output text) LAMBDA_ARN=$(aws cloudformation describe-stacks --stack-name lambda-stack --query "Stacks[0].Outputs[?OutputKey=='MyLambdaArn'].OutputValue" --output text) # 创建API资源与方法 RESOURCE_ID=$(aws apigateway create-resource --rest-api-id $REST_API_ID --parent-id $(aws apigateway get-resources --rest-api-id $REST_API_ID --query "items[?path=='/'].id" --output text) --path-part "dynamic-path" --query "id" --output text) aws apigateway put-method --rest-api-id $REST_API_ID --resource-id $RESOURCE_ID --http-method POST --authorization-type NONE aws apigateway put-integration --rest-api-id $REST_API_ID --resource-id $RESOURCE_ID --http-method POST --type AWS_PROXY --integration-http-method POST --uri "arn:aws:apigateway:${AWS_REGION}:lambda:path/2015-03-31/functions/${LAMBDA_ARN}/invocations" # 添加Lambda调用权限 aws lambda add-permission --function-name $LAMBDA_ARN --statement-id api-gateway-permission --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn "arn:aws:execute-api:${AWS_REGION}:${AWS_ACCOUNT_ID}:${REST_API_ID}/${STAGE_NAME}/*" # 重新部署API aws apigateway create-deployment --rest-api-id $REST_API_ID --stage-name $STAGE_NAME
内容的提问来源于stack exchange,提问作者Karen Kostanyan
相关产品推荐
相关产品推荐

