如何在更新参数时强制 CloudFormation 堆栈更新?
Posted
技术标签:
【中文标题】如何在更新参数时强制 CloudFormation 堆栈更新?【英文标题】:How do I force a CloudFormation stack to update when the parameter is updated? 【发布时间】: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更新栈?
【问题讨论】:
【参考方案1】:CloudFormation 不会更新堆栈,除非堆栈中已创建资源的属性发生更改。
例如: 考虑我有一个简单的模板来创建一个需要传递 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)
如果您已经使用Metadata
和AWS::CloudFormation::Init
,则不会立即更新数据。据我所知,这是更改Metadata
值后要更改的数据的条件。
cfn-init
命令
等待大约 15 分钟,因为检查 Metadata
更改的守护进程每 15 分钟检查一次更改。
【讨论】:
以上是关于如何在更新参数时强制 CloudFormation 堆栈更新?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 CloudFormation 上将 DynamoDB 读/写容量模式设置为按需
CloudFormation yaml - 如何强制数字类型?
CloudFormation 不会在更新时部署到 API 网关阶段
将对象上传到 S3 存储桶时如何触发 AWS Cloudformation 堆栈的更新?