以下 AWS CloudFormation 给出了循环依赖项错误。我的理解是依赖项是这样的:rawUploads -> generatePreview -> previewPipeline -> rawUploads
.虽然看起来rawUploads
并不取决于generatePreview
,但我想 CF 需要知道在创建存储桶时要触发的 lambda,即使触发器是在 CloudFormation 模板的 lambda 部分中定义的。
我在网上找到了一些讨论类似问题的资源,但它似乎不适用于这里。 https://aws.amazon.com/premiumsupport/knowledge-center/unable-validate-circular-dependency-cloudformation/
我有哪些选择来打破这个循环依赖链?可编写脚本的解决方案是可行的,但手动更改的多个部署不适合我的用例。
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
rawUploads:
Type: 'AWS::S3::Bucket'
previewAudioFiles:
Type: 'AWS::S3::Bucket'
generatePreview:
Type: AWS::Serverless::Function
Properties:
Handler: generatePreview.handler
Runtime: nodejs6.10
CodeUri: .
Environment:
Variables:
PipelineId: !Ref previewPipeline
Events:
BucketrawUploads:
Type: S3
Properties:
Bucket: !Ref rawUploads
Events: 's3:ObjectCreated:*'
previewPipeline:
Type: Custom::ElasticTranscoderPipeline
Version: '1.0'
Properties:
ServiceToken:
Fn::Join:
- ":"
- - arn:aws:lambda
- Ref: AWS::Region
- Ref: AWS::AccountId
- function
- aws-cloudformation-elastic-transcoder-pipeline-1-0-0
Name: transcoderPipeline
InputBucket:
Ref: rawUploads
OutputBucket:
Ref: previewAudioFiles
一种方法是为 S3 存储桶指定显式名称,以便以后您可以简单地使用存储桶名称,而不是依赖Ref: bucketname
。如果您想要自动生成的存储桶名称,这显然是有问题的,在这些情况下,谨慎的做法是从某个前缀加上(唯一(堆栈名称生成存储桶名称,例如:
InputBucket: !Join ["-", ['rawuploads', Ref: 'AWS::StackName']]
另一种选择是使用单个 CloudFormation 模板,但分 2 个阶段 - 第一阶段创建基础资源(以及任何非循环的引用(,然后将剩余的引用添加到模板并进行堆栈更新。显然不理想,所以我更喜欢第一种方法。
在需要引用 ARN 的情况下,您还可以使用第一种技术,例如:
!Join ['/', ['arn:aws:s3:::logsbucket', 'AWSLogs', Ref: 'AWS:AccountId', '*']]
使用此技术时,您可能还需要考虑使用 DependsOn,因为您已经删除了有时会导致问题的隐式依赖项。
这篇文章最终帮助了我:https://aws.amazon.com/premiumsupport/knowledge-center/unable-validate-destination-s3/
我最终在CloudFormation中配置了一个SNS主题。存储桶将推送有关此主题的事件,而 Lambda 函数将侦听此主题。这样,依赖关系图如下所示:
S3 bucket -> SNS topic -> SNS topic policy
Lambda function -> SNS topic
Lambda function -> transcoder pipeline
与此类似的内容(省略了一些政策(
AWSTemplateFormatVersion: '2010-09-09'
Transform: 'AWS::Serverless-2016-10-31'
Resources:
SNSTopic:
Type: AWS::SNS::Topic
SNSTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
PolicyDocument:
Id: MyTopicPolicy
Version: '2012-10-17'
Statement:
- Sid: Statement-id
Effect: Allow
Principal:
AWS: "*"
Action: sns:Publish
Resource:
Ref: SNSTopic
Condition:
ArnLike:
aws:SourceArn:
!Join ["-", ['arn:aws:s3:::rawuploads', Ref: 'AWS::StackName']]
Topics:
- Ref: SNSTopic
rawUploads:
Type: 'AWS::S3::Bucket'
DependsOn: SNSTopicPolicy
Properties:
BucketName: !Join ["-", ['rawuploads', Ref: 'AWS::StackName']]
NotificationConfiguration:
TopicConfigurations:
- Topic:
Ref: "SNSTopic"
Event: 's3:ObjectCreated:*'
previewAudioFiles:
Type: 'AWS::S3::Bucket'
generatePreview:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Join ["-", ['generatepreview', Ref: 'AWS::StackName']]
Handler: generatePreview.handler
Runtime: nodejs6.10
CodeUri: .
Environment:
Variables:
PipelineId: !Ref previewPipeline
Events:
BucketrawUploads:
Type: SNS
Properties:
Topic: !Ref "SNSTopic"
previewPipeline:
Type: Custom::ElasticTranscoderPipeline
DependsOn: 'rawUploads'
Version: '1.0'
Properties:
ServiceToken:
Fn::Join:
- ":"
- - arn:aws:lambda
- Ref: AWS::Region
- Ref: AWS::AccountId
- function
- aws-cloudformation-elastic-transcoder-pipeline-1-0-0
Name: transcoderPipeline
InputBucket:
!Join ["-", ['arn:aws:s3:::rawuploads', Ref: 'AWS::StackName']]
OutputBucket:
Ref: previewAudioFiles