如何在参数更新时强制CloudFormation堆栈更新?

时间:2017-10-19 06:52:51

标签: amazon-web-services amazon-ec2 amazon-cloudformation autoscaling

我正在运行AWS CloudFormation堆栈,该堆栈接收一些参数并启动EC2实例以及其他AWS资源。这些参数被输入EC2实例的用户数据,并基于这些更改动态地发送到驻留在EC2实例上的Web应用程序。

CFN Parameters

UserData: 
      Fn::Base64: 
        Fn::Join: 
          - ""
          - 
            - "#!/bin/bash \n"
            - "sh website-conf/website_mysql_config.sh "
            - " -c \""
            - 
              Ref: "CompanyName"

如上例所示,CompanyName是传递给userdata脚本的众多参数之一。问题是,当更新任何一个或多个参数时,CloudFormation不会检测到这一点,而是会抛出此错误。

CFN Error

因此,为了更新堆栈,我必须编辑堆栈并对ASG进行更改,以便CloudFormation看到'更改并执行堆栈更新。

有没有办法在参数更新时强制CFN更新堆栈?

3 个答案:

答案 0 :(得分:5)

CloudFormation不会更新堆栈,除非在堆栈中已经创建了 属性

例如: 考虑我有一个简单的模板来创建一个数据库,我需要传递2个参数:

  1. DB-名称
  2. 区域
  3. 假设我使用db-name将其作为值传递给DBInstanceIdentifier

    还假设我没有以任何方式使用输入参数region来创建堆栈的资源(或其属性)。它更像是为了可读性而保留的伪参数。

    我将(TEST-DB1, us-east-1)作为输入参数传递给CloudFormation模板,并成功创建了资源。

    Scenario-1: 现在,如果我更新堆栈(仍然使用现有模板),只需将输入参数更改为(TEST-DB2, us-east-1)。即:只更改db-name而不是区域。然后,CloudFormation将检测到此参数更新会导致堆栈运行资源的属性发生变化,并将修改计算并显示为更改集。

    Scenario-2: 假设我进行了另一次更新(仍然使用现有模板)属性,只需将输入参数更改为(TEST-DB1, us-east-2)。即:仅更改区域而不是db-name。然后,CloudFormation将检测到,此参数更新导致堆栈中运行资源属性的没有变化将显示Error creating change set

    <强> 底线: 您对输入参数的更改必须导致更新/替换堆栈的任何资源(或其属性,如安全组,端口等..)。然后,AWS CloudFormation会将其显示为Change Sets以供您查看。此外,AWS CloudFormation使用的方法(更新或替换)取决于您为给定资源类型更新的属性。

      

    您的参数&#34; CompanyName&#34;没有对运行进行任何更改   堆栈的资源。因此报告为Error creating change set。您需要使用它来创建堆栈的任何资源/资源属性。然后,CloudFormation将在您修改它时检测更改集。这同样适用于您使用的任何其他输入参数。

答案 1 :(得分:2)

使用AWS CLI Update-Stack命令。如果您使用AWS CLI,则可以将参数注入堆栈,因此对任何参数的任何更改都会导致新堆栈。我自己这样做是为了将Git /版本提交ID注入到UserData中,因此只需将更改提交给堆栈,JSON / Yaml就会允许堆栈更新。对参数文件的任何更改都将允许堆栈更新,甚至只是注释。我在UserData中引用我的Git提交ID的方式与引用Ref:CompanyName的方式相同,所以当我更改Git提交ID时,userData部分会在堆栈更新时更新。

更新堆栈命令

aws cloudformation update-stack --stack-name MyStack --template-body file:///Users/Documents/Git/project/cloudformation/stack.json --parameters file:///Users/Documents/Git/project/cloudformation/parameters/stack-parameters.dev.json --capabilities CAPABILITY_IAM

<强>过程

使用此方法,您可以将参数更改为参数json或yaml文件,然后将其检入版本控制。现在,如果您使用构建服务器,则可以通过检查master并仅运行上面的一行来更新堆栈。使用AWS CodeBuild可以轻松实现这一目标,因此您不需要jenkins。

答案 2 :(得分:1)

您的问题的答案已经通过此状态得到解答,除非已在堆栈中创建的资源属性发生更改,否则CloudFormation不会更新堆栈。

有关您问题的答案,请查看以下说明。

有一种方法可以强制Cloudformation使用AWS::CloudFormation::Init更新堆栈。 通过使用cfn-init,每个实例在检测到AWS::CloudFormation::Init在元数据中所做的更改时都可以自行更新。

我们必须首先理解一个概念,即UserData和元数据之间的差异,至少在AWS::CloudFormation::Init情况下。

  • Userdata:仅在第一次启动实例时调用一次(这包括需要更换实例的更新)。因此,如果您更新堆栈(而不是创建新堆栈),即使您更改参数值,如果您在UserData下调用参数,也不会更改任何内容。
  • Metadata:可以随时更新。要使其工作,您必须确保检测到更改的元数据的守护程序正在运行(守护程序称为cfn-hup)

如果您已使用MetadataAWS::CloudFormation::Init,则不会立即更新数据。据我所知,这是更改Metadata值后要更改的数据的条件。

  • 重新启动实例
  • 使用它的参数
  • 再次运行cfn-init命令
  • 等待大约15分钟,因为检查Metadata中的更改的守护程序是在15分钟内检查一次更改。