问题描述
首先,我对 Cloud Formation 非常陌生。我正在尝试构建一个模板,该模板将部署一个具有两个服务的相当简单的环境。
我需要一个 S3 存储桶,它可以在创建对象时向 SQS 触发消息。创建这些资产时,S3 配置必须包含指向 SQS 队列的指针。但是 SQS Queue 必须有专门允许 S3 存储桶权限的策略。这会产生循环依赖。为了打破这个圈子,我想做到以下几点:
- 创建 S3 存储桶
- 创建 SQS 队列,引用 S3 存储桶
- 修改 S3 存储桶以引用 SQS 队列。
当我尝试这个时,我收到一条错误消息,告诉我它找不到 SQS 队列。当我在 #3 中放入 DependsOn 命令时,它会在循环依赖中出错。
您能否声明一个资源,稍后在模板中使用新参数重新声明它?如果是这样,你会怎么做。我这样做错了吗?
解决方法
在这种情况下导致循环依赖的原因是使用了诸如 Ref 或 Fn::GetAtt 之类的内在函数,这些函数要求参考资源可用。为避免这种情况,您可以在不引用资源的情况下指定资源 ARN。这是一个示例模板,其中 CloudFormation 执行以下操作:
- 创建队列
- 添加队列策略以向不存在的存储桶授予权限
- 创建存储桶
模板:
Parameters:
BucketName:
Description: S3 Bucket name
Type: String
Default: mynewshinybucket
Resources:
Queue:
Type: AWS::SQS::Queue
QueuePolicy:
Type: AWS::SQS::QueuePolicy
Properties:
Queues:
- !Ref Queue
PolicyDocument:
Statement:
- Effect: Allow
Action: SQS:SendMessage
Resource: !GetAtt Queue.Arn
Principal:
AWS: '*'
Condition:
ArnLike:
# Specify bucket ARN by referring to a parameter instead of the actual bucket resource which does not yet exist
aws:SourceArn: !Sub arn:aws:s3:::${BucketName}
Bucket:
Type: AWS::S3::Bucket
# Create the bucket after the queue policy to avoid "Unable to validate the following destination configurations" errors
DependsOn: QueuePolicy
Properties:
BucketName: !Ref BucketName
NotificationConfiguration:
QueueConfigurations:
- Event: 's3:ObjectCreated:Put'
Queue: !GetAtt Queue.Arn
编辑: 当使用 Ref/GetAtt/Sub 从另一个资源检索值时,所有这些都需要该资源可用。 CloudFormation 将确保始终在引用资源之后创建使用该函数的资源。通过这种方式检测循环依赖。 Sub 用于字符串替换,但在与参数或资源 (Source) 一起使用时,其工作方式与 Ref 完全相同。
关键是我们指的是一个参数(而不是一个资源),它总是可用的。 在这种情况下,使用 Sub 稍微简单一些,因为使用 Ref 需要额外的 Join。例如,这会给你相同的结果:
aws:SourceArn: !Join
- ''
- - 'arn:aws:s3:::'
- !Ref BucketName
另一种方法是在不使用任何内在函数的情况下对存储桶 ARN 进行硬编码。重要的是不要引用bucket本身以避免循环依赖。