我正在尝试使用 AWS 自动扩展生命周期钩子在封装以下内容的模板中:
AWS::AutoScaling::AutoScalingGroup
具有相关的扩大/缩小策略、启动配置、IAM 角色等。- 2
AWS::AutoScaling::LifecycleHook
用于 EC2 启动/终止事件。 AWS::SQS::Queue
(在一个简化的例子中)生命周期通知被发布的地方。AWS::IAM::Role
自动缩放组向 SQS 队列发布通知的角色。
当 ASG 启动时,队列最终会收到两个来自生命周期挂钩创建过程的测试通知,但没有实例启动的通知。
这是竞争条件。
AWS::AutoScaling::LifecycleHook
对象引用AWS::AutoScaling::AutoScalingGroup
(因此依赖于它)。这决定了 CloudFormation 创建资源的顺序(首先创建组)。
问题在于,组在钩子创建完成之前就开始启动实例(实例启动不是模板的一部分,因此它开始并行执行)。在创建钩子时,没有更多事件可发布,因为实例已经创建。
有什么办法可以解决这个问题并在堆栈启动时捕获启动事件?
答案1
这不是一个理想的解决方案,但两次堆栈创建是否是一个有效的解决方法?
- 在初始堆栈创建时将资源
DesiredCapacity
中的属性设置为。这样无需实际启动任何实例即可创建、和资源。AutoScalingGroup
0
LaunchConfiguration
AutoScalingGroup
LifecycleHook
- 在后续堆栈更新中设置
DesiredCapacity
为所需的数量 (> )。这应该在创建后启动所需的实例。0
LifecycleHook
答案2
另一个解决方法是执行与 Will Jordan 建议的类似操作,但这可以作为同一个 CloudFormation Stack 更新的一部分:
- 在初始堆栈创建时将 AutoScalingGroup 资源中的 DesiredCapacity 属性设置为 0。这样无需实际启动任何实例即可创建 LaunchConfiguration、AutoScalingGroup 和 LifecycleHook 资源。
- 创建一个依赖于 LifecycleHook 的 AWS::AutoScaling::ScheduledAction,并设置所需的大小和重复次数:
* * * * *
这些资源可以是单个 Cloudformation 脚本的一部分,无需在 Stack 上执行多次更新。
[编辑]:不幸的是,这种方法会导致在满足重复 cron 表达式时出现实例。AutoScaling 组需要在 AutoScaling 组 UpdatePolicy 的 AutoScalingScheduledAction 中将 IgnoreUnmodifiedGroupSizeProperties 设置为“true” (https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-attribute-updatepolicy.html#cfn-attributes-updatepolicy-scheduledactions)。
答案3
自从提出这个问题以来,AWS 增加了一个生命周期钩子规范列表财产AWS::AutoScaling::AutoScalingGroupcloudformation 资源,它允许您在 ASG 本身的定义中指定生命周期钩子列表,而不是稍后关联它们。这解决了竞争条件,或多或少与 @brett 在其评论中所建议的方式完全一致。
我在遵循以下方法时遇到了完全相同的问题AWS 博客文章耗尽 ECS 容器以避免终止 EC2 实例(此问题中存在相同的竞争条件)。就我而言,我试图定义一个终止钩子,让 ECS 有时间在 ASG 中终止旧容器之前在新实例上启动新容器,但当我使用 cloudformation 更新 ASG 本身时,它不起作用,因为 Cloudformation 在需要钩子之前几秒就删除了它。将钩子移到自动缩放组定义内解决了我的问题。
答案4
不确定这是否有效,但看起来您可能能够使用NotificationConfiguration
ASG 资源获得类似的结果。
NotificationConfiguration 可以向已订阅 SQS 队列的 SNS 主题发送通知。显然,pending
采用这种方法,生命周期将顺利进行,无需等待complete-lifecycle-action
,但至少所有实例启动都将在队列中可用。
高血压
编辑
另一个选择可能是使用WaitCondition
或CreationPolicy
- 不确定这些是否会在处理生命周期挂钩之前应用。