基于AWS SAM构建API遇CloudFormation栈资源超限问题求助
First, let's recap the core issue: your original SAM template grew too large, exceeding CloudFormation's default single-stack resource limit (200 resources). Splitting the templates is the right approach, but your buildspec wasn't configured to handle multi-stack deployments correctly. Here are two proven solutions tailored to your scenario:
Solution 1: Use CloudFormation Nested Stacks (Recommended for Tightly Coupled Resources)
Nested stacks let you manage multiple sub-stacks from a single master stack, which keeps your deployment workflow clean while spreading resources across multiple stacks. Here's how to set it up:
Split Your Templates
- Create a master template (e.g.,
master-template.yml) that acts as the root stack. - Move subsets of your resources into separate sub-stack templates (e.g.,
api-gateway.yml,lambda-functions.yml,dynamodb-resources.yml).
- Create a master template (e.g.,
Link Sub-Stacks in the Master Template
Inmaster-template.yml, reference each sub-stack using theAWS::CloudFormation::Stackresource. Pass any required parameters between stacks:Resources: ApiGatewayStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub 'https://${S3Bucket}.s3.${AWS::Region}.amazonaws.com/${S3Prefix}/packaged-api-gateway.yml' Parameters: Environment: !Ref Environment LambdaFunctionsStack: Type: AWS::CloudFormation::Stack Properties: TemplateURL: !Sub 'https://${S3Bucket}.s3.${AWS::Region}.amazonaws.com/${S3Prefix}/packaged-lambda-functions.yml' Parameters: ApiGatewayRestApiId: !GetAtt ApiGatewayStack.Outputs.RestApiIdUpdate buildspec.yml to Package All Templates
Modify your buildspec to package every template (master + sub-stacks) and upload them to your S3 bucket:version: 0.2 phases: build: commands: # Package master template - aws cloudformation package --template-file master-template.yml --s3-bucket $S3_BUCKET --s3-prefix sam-deploy --output-template-file packaged-master.yml # Package sub-stacks - aws cloudformation package --template-file api-gateway.yml --s3-bucket $S3_BUCKET --s3-prefix sam-deploy --output-template-file packaged-api-gateway.yml - aws cloudformation package --template-file lambda-functions.yml --s3-bucket $S3_BUCKET --s3-prefix sam-deploy --output-template-file packaged-lambda-functions.yml artifacts: files: - packaged-master.yml - packaged-api-gateway.yml - packaged-lambda-functions.ymlDeploy the Master Stack
In your CodeStar deployment pipeline, only deploy thepackaged-master.ymltemplate. CloudFormation will automatically create/update all linked sub-stacks, and resources will be spread across multiple stacks to avoid the limit.
Solution 2: Deploy Independent Stacks (For Decoupled Resources)
If your resources don't need tight integration, you can deploy two completely separate stacks. This requires handling cross-stack references explicitly:
Split Templates into Independent Units
Create two standalone templates (e.g.,stack-1.ymlandstack-2.yml), ensuring each has fewer than 200 resources. Define outputs in the first stack for any resources the second stack needs (e.g., API Gateway ID, Lambda ARN).Update buildspec.yml to Deploy Both Stacks
Modify the buildspec to package both templates, then deploy them sequentially (wait for the first stack to finish before deploying the second):version: 0.2 phases: build: commands: # Package both templates - aws cloudformation package --template-file stack-1.yml --s3-bucket $S3_BUCKET --output-template-file packaged-stack-1.yml - aws cloudformation package --template-file stack-2.yml --s3-bucket $S3_BUCKET --output-template-file packaged-stack-2.yml post_build: commands: # Deploy first stack - aws cloudformation deploy --template-file packaged-stack-1.yml --stack-name sam-api-stack-1 --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM # Wait for stack to stabilize (handles creates and updates) - aws cloudformation wait stack-create-complete --stack-name sam-api-stack-1 || aws cloudformation wait stack-update-complete --stack-name sam-api-stack-1 # Fetch output from first stack for second stack - API_ID=$(aws cloudformation describe-stacks --stack-name sam-api-stack-1 --query 'Stacks[0].Outputs[?OutputKey==`RestApiId`].OutputValue' --output text) # Deploy second stack with the fetched parameter - aws cloudformation deploy --template-file packaged-stack-2.yml --stack-name sam-api-stack-2 --capabilities CAPABILITY_IAM CAPABILITY_NAMED_IAM --parameters ParameterKey=ApiId,ParameterValue=$API_ID artifacts: files: - packaged-stack-1.yml - packaged-stack-2.yml
Key Tips to Avoid Pitfalls
- Verify Resource Counts: Use
aws cloudformation validate-template --template-body file://your-template.ymlto check how many resources each template contains, ensuring they stay under the 200 limit (you can request a limit increase via AWS Support, but splitting is better practice). - CodeStar Environment Variables: Make sure
$S3_BUCKETand other variables in your buildspec are correctly populated by CodeStar's project configuration. - SAM Compatibility: Sub-stacks can still be SAM templates—
aws cloudformation packagewill handle SAM-to-CloudFormation conversion for all templates. - Rollback Controls: Add
--no-fail-on-empty-changesetto your deploy commands to avoid pipeline failures when there are no changes. You can also configure rollback behavior with--rollback-configuration.
内容的提问来源于stack exchange,提问作者Qais Abou Jaoudé

