【问题标题】:How do I force a CloudFormation stack to update when the parameter is updated?如何在更新参数时强制 CloudFormation 堆栈更新?
【发布时间】:2018-03-31 03:41:20
【问题描述】:

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

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

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

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

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

【问题讨论】:

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


    【解决方案1】:

    CloudFormation 不会更新堆栈,除非堆栈中已创建资源的属性发生更改

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

    1. 数据库名称
    2. 地区

    假设我使用db-name 将其作为值传递给DBInstanceIdentifier

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

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

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

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

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

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

    【讨论】:

      【解决方案2】:

      使用 AWS CLI 更新堆栈命令。如果您使用 AWS CLI,您可以将参数注入您的堆栈,因此对任何参数的任何更改都会生成一个新堆栈。我自己这样做是为了将 Git/版本提交 ID 注入到 UserData 中,因此只需将堆栈的 JSON/Yaml 更改提交到 Git 即可允许堆栈更新。对参数文件的任何更改都将允许堆栈更新,即使只是一个注释。我在 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。

      【讨论】:

      • 当您说“对任何参数的任何更改都会导致新堆栈”时,您的意思是堆栈已更新还是完全形成了新堆栈?
      • 对我的 parameters.json 文件中的任何参数的任何更改都将允许堆栈更新。堆栈保持不变,但 update-stack 命令将被接受,并且您当前遇到的错误不会发生。
      • 查看我的最后评论。我做了一些编辑来澄清。
      【解决方案3】:

      您的问题的答案已经在此状态下得到解答,除非堆栈中已创建的资源的属性发生变化,否则 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 分钟检查一次更改。

      【讨论】:

        猜你喜欢
        • 2021-06-27
        • 2018-09-11
        • 2017-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-26
        • 2018-06-03
        • 2019-10-27
        相关资源
        最近更新 更多