CloudFormation,在 DependsOn 上应用条件

Posted

技术标签:

【中文标题】CloudFormation,在 DependsOn 上应用条件【英文标题】:CloudFormation, apply Condition on DependsOn 【发布时间】:2016-04-09 00:42:15 【问题描述】:

我需要做的任务是让 CDN 依赖于 S3 存储桶。但我们想让它使用现有的存储桶,而不是创建一个新存储桶。

这是我正在尝试的示例代码:

"Parameters" : 
  "UseExistingBucket" : 
    "Description" : "Yes/No",
    "Default" : "yes",
    "Type" : "String",
    "AllowedValues" : [ "yes", "no" ]
  
,
"Conditions" : 
  "CreateS3Resources" : "Fn::Equals" : ["Ref" : "UseExistingBucket", "no"]
,
"Resources" : 
  "StaticBucket" : 
    "Type" : "AWS::S3::Bucket",
    "Condition" : "CreateS3Resources",
    "Properties" : 
      "BucketName" :  "Fn::Join": [ "-", [ "app",   "Ref": "EnvType" , "static" ] ] 
    ,
    "DeletionPolicy": "Retain"
  ,
  "MyStaticDistribution": 
    "Type": "AWS::CloudFront::Distribution",
    "Properties": 
      "DistributionConfig": 
        "Origins": [
          
            "DomainName": 
              "Fn::If" : [
                "CreateS3Resources",
                 "Fn::Join": [ "-", [ "app",   "Ref": "EnvType" , "static" ] ] ,
                "Fn::GetAtt": [ "StaticBucket", "DomainName" ] 
              ]
            ,
            "Id": "S3Origin",
          
        ]
      
    ,
    "DependsOn": [
      "Fn::If" : [
        "CreateS3Resources",
         "Fn::Join": [ "-", [ "app",   "Ref": "EnvType" , "static" ] ] ,
        ""
      ]
    ]
  

如果需要,请向我建议更多详细信息(至少 *** 确实需要更多详细信息,但我没有指定任何:-P)

【问题讨论】:

【参考方案1】:

您可以使用 Fn:GetAtt 包裹在条件 Fn:If 中来执行此操作。 使用 Fn:GetAtt 意味着依赖,因此 CloudFormation 将在到达该函数后自动等待,就像您使用 DependsOn 一样。

示例

下面的代码 sn-p 通过有条件地检索尚未创建的嵌套堆栈的名称来显示这一点,但只有在条件 UseNestedStack 设置为 true 时才会这样做。如果 UseNestedStack 为 false,它不会等待,而是检索一个局部变量名。


"Fn::If": ["UseNestedStack", 
    "Fn::GetAtt": ["NestedStack", "Outputs.Name"]
, 
    "Ref": "LocalName"
]

我怎么知道这个? (另一个例子)

不幸的是,没有官方文档正式说明这一点,但 AWS 告诉我这样做,在他们的代码示例中,您可以看到当订单很重要时,他们使用 Fn:GetAtt。我已经尝试了很多次,并且每次都有效。在一个简单的堆栈上自己尝试一下。这是我调整并自己使用的 AWS lambda 示例的更多伪证明。如果 AMI 函数是在资源 AMI 信息之后创建的,则下面的堆栈可能无法工作,AMI 信息需要 AMI 函数的输出,因此 AWS 使用 Fn:GetAtt 将它们链接在一起。要查看此滚动到底部并查看资源 AMIInfo,您将看到它通过 fn: Gett 引用了 AMIFunction。 CloudFormation 看到这一点并返回到 AMIFunction 以首先创建它。

"AMIInfoFunction": 
  "DependsOn":"SourceStack",
  "Type": "AWS::Lambda::Function",
  "Properties": 
    "Code": 
      "S3Bucket":  "Ref": "DeploymentBucket" ,
      "S3Key": "Fn::Join": [
        "",
        [
          
            "Ref": "ApplicationName"
          ,
          "/amilookup.zip"
        ]
      ]
    ,
    "Handler": "amilookup.handler",
    "Runtime": "nodejs",
    "Timeout": "30",
    "Role":  "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] ,
    "VpcConfig": 
      "SecurityGroupIds": [ "Ref": "InstanceSecurityGroup"],
      "SubnetIds": [ "Ref":"PrivateSubnetA","Ref":"PrivateSubnetB" ]
    
  
,
"AMIInfo": 
  "Type": "Custom::AMIInfo",
  "Properties": 
    "ServiceToken":  "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] ,
    "StackName":  "Ref":"SourceStack" 
  

更新: 现在在相关堆栈的文档中记录了 (Fn::GetAtt)。感谢 cmets 中的 idoimaging 指出这一点。 https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-dependson.html

【讨论】:

是否有文档表明 GetAtt 会在继续前自动等待其他资源完成? @doeiqts 好问题。不幸的是,我没有看到它记录在案,但我相信从它在 AWS 示例中的使用,我已经多次看到它工作的事实,以及 AWS 工程师指示我这样做的事实,这是真的。我从 AWS 添加了一个 lambda 示例,它们以这种方式延迟创建。但是是的,一些官方文档会更干净。 这现在是!GetAtt 的一个记录功能:docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/… @idoimaging 感谢您指出这一点。我已将您的链接添加到答案中。我不敢相信那是 5 年前的事了哈哈。【参考方案2】:

在您的模板中,您不需要将 DependsOn 属性添加到您的 MyStaticDistribution 资源,因为您已经拥有对 StaticBucket 资源的引用。

这在优化 AWS CloudFormation 模板博文Specifying Dependencies部分中有记录: https://aws.amazon.com/blogs/devops/optimize-aws-cloudformation-templates/

When you need CloudFormation to wait to provision one resource until another one has been provisioned, you can use the DependsOn attribute.

You can also introduce references between elements by using either the "Ref": "MyResource" or the "Fn::GetAtt" : [ "MyResource" , "MyAttribute" ] functions. When you use one of these functions, CloudFormation behaves as if you’ve added a DependsOn attribute to the resource.

【讨论】:

【参考方案3】:

对于yaml用户,也可以使用:

Conditions:
  CreateConfigRecorder: !Equals [ !Ref ConfigRecorderExists, 'false' ]

Resource:
#my 1st AWS Resource
  ConfigRecorder: 
    Condition: CreateConfigRecorder
    Type: AWS::Config::ConfigurationRecorder
    *more codes below*

#added, since DependsOn: !If is not possible, trigger by WaitCondition if CreateConfigRecorder is true
#Hacks: https://garbe.io/blog/2017/07/17/cloudformation-hacks/
  ConfigRecorderWaitHandle: 
    Condition: CreateConfigRecorder
    DependsOn: ConfigRecorder
    Type: "AWS::CloudFormation::WaitConditionHandle"
#added, since DependsOn: !If is not possible, trigger by WaitCondition if CreateConfigRecorder is false
  WaitHandle: 
    Type: "AWS::CloudFormation::WaitConditionHandle"
#added, since DependsOn: !If is not possible
  WaitCondition: 
    Type: "AWS::CloudFormation::WaitCondition"
    Properties: 
      Handle: !If [CreateConfigRecorder, !Ref ConfigRecorderWaitHandle, !Ref WaitHandle]
      Timeout: "1"
      Count: 0
#my 2nd AWS Resource that requires DependsOn Attribute
  AWSConfigRule:
    Type: AWS::Config::ConfigRule
    DependsOn: WaitCondition #added, since DependsOn: !If is not possible
    *more codes below*

在运行 CFN 之前,如果我的第一个资源不存在,我的第二个资源基本上只有 DependsOn 属性。我来自:https://garbe.io/blog/2017/07/17/cloudformation-hacks/

【讨论】:

【参考方案4】:

要扩展上述@Usman Mutawakil 的答案,您可以在标签中使用 GetAtt 来隐式施加 DependsOn 条件。

例如,在我们的例子中,我们使用 lambda 函数在一段时间后自动删除暂存堆栈。此 func 仅部署在 staging 上,必须在堆栈中最后删除。

  ShopCluster:
    Type: 'AWS::ECS::Cluster'
    Properties:
      ...
      Tags:
        - Key: ConditionalDependsOn
          Value: !If [IsStaging, !GetAtt DeleteShopStackLambda.Arn, Ignored]

【讨论】:

【参考方案5】:

您不能将函数附加到 DependsOn 属性。

但您可以通过使用AWS::CloudFormation::WaitConditionAWS::CloudFormation::WaitConditionHandle 将条件应用于 DependsOn 属性和解决方法

完整示例:

Parameters:
  ContainerPort:
    Type: String
    Default: ''
    Description: HTTP Port of the container

Conditions:
  HasAlb: !Not [ !Equals [ !Ref ContainerPort, '']]

Resources:

  ALBListenerRule:
    Type: AWS::ElasticLoadBalancingV2::ListenerRule
    Condition: HasAlb
    Properties:
      ...


  AlbWaitHandle: 
    Condition: HasAlb
    DependsOn: ALBListenerRule
    Type: "AWS::CloudFormation::WaitConditionHandle"

  WaitHandle: 
    Type: "AWS::CloudFormation::WaitConditionHandle"

  WaitCondition: 
    Type: "AWS::CloudFormation::WaitCondition"
    Properties: 
      Handle: !If [HasAlb, !Ref AlbWaitHandle, !Ref WaitHandle]
      Timeout: "1"
      Count: 0

  Application:
    Type: AWS::ECS::Service
    DependsOn: WaitCondition

原答案可以在here找到

【讨论】:

以上是关于CloudFormation,在 DependsOn 上应用条件的主要内容,如果未能解决你的问题,请参考以下文章

CloudFormation 嵌套堆栈名称

CloudFormation 的超时配置

在 CloudFormation 中将 Cognito 验证类型设置为链接

在哪里可以找到 CloudFormation 日志流

VPC 内部的 CloudFormation?

如何为在 Cloudformation 中创建的 Lambda 设置 Cloudwatch 日志