有没有办法使用 CloudFormation 创建没有竞争条件的 AWS 自动扩展生命周期挂钩?

有没有办法使用 CloudFormation 创建没有竞争条件的 AWS 自动扩展生命周期挂钩?

我正在尝试使用 AWS 自动扩展生命周期钩子在封装以下内容的模板中:

  1. AWS::AutoScaling::AutoScalingGroup具有相关的扩大/缩小策略、启动配置、IAM 角色等。
  2. 2AWS::AutoScaling::LifecycleHook用于 EC2 启动/终止事件。
  3. AWS::SQS::Queue(在一个简化的例子中)生命周期通知被发布的地方。
  4. AWS::IAM::Role自动缩放组向 SQS 队列发布通知的角色。

当 ASG 启动时,队列最终会收到两个来自生命周期挂钩创建过程的测试通知,但没有实例启动的通知。

这是竞争条件。

AWS::AutoScaling::LifecycleHook对象引用AWS::AutoScaling::AutoScalingGroup(因此依赖于它)。这决定了 CloudFormation 创建资源的顺序(首先创建组)。

问题在于,组在钩子创建完成之前就开始启动实例(实例启动不是模板的一部分,因此它开始并行执行)。在创建钩子时,没有更多事件可发布,因为实例已经创建。

有什么办法可以解决这个问题并在堆栈启动时捕获启动事件?

答案1

这不是一个理想的解决方案,但两次堆栈创建是否是一个有效的解决方法?

  1. 在初始堆栈创建时将资源DesiredCapacity中的属性设置为。这样无需实际启动任何实例即可创建、和资源。AutoScalingGroup0LaunchConfigurationAutoScalingGroupLifecycleHook
  2. 在后续堆栈更新中设置DesiredCapacity为所需的数量 (> )。这应该在创建后启动所需的实例。0LifecycleHook

答案2

另一个解决方法是执行与 Will Jordan 建议的类似操作,但这可以作为同一个 CloudFormation Stack 更新的一部分:

  1. 在初始堆栈创建时将 AutoScalingGroup 资源中的 DesiredCapacity 属性设置为 0。这样无需实际启动任何实例即可创建 LaunchConfiguration、AutoScalingGroup 和 LifecycleHook 资源。
  2. 创建一个依赖于 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

不确定这是否有效,但看起来您可能能够使用NotificationConfigurationASG 资源获得类似的结果。

NotificationConfiguration 可以向已订阅 SQS 队列的 SNS 主题发送通知。显然,pending采用这种方法,生命周期将顺利进行,无需等待complete-lifecycle-action,但至少所有实例启动都将在队列中可用。

高血压

编辑

另一个选择可能是使用WaitConditionCreationPolicy- 不确定这些是否会在处理生命周期挂钩之前应用。

相关内容