通过自定义终止策略,让AWS自动伸缩组(ASG)始终终止最旧的实例

2 分钟阅读
内容级别:中级
3

本文利用AWS自动伸缩组(ASG)的自定义终止策略,一致地终止最旧的实例,解决了默认ASG设置中的限制,即实例在不同可用区的分布可能会覆盖最旧终止逻辑。文章介绍了一个解决方案,该方案集成了Lambda函数和CloudFormation,以简化部署和提高操作效率,确保缩容活动可预测且易于管理。

背景:

AWS自动伸缩组(ASGs)提供多种终止策略,包括旨在首先退役最旧实例的OldestInstance策略。然而,ASGs优先在各个可用区(AZ)之间平等分配实例。这种行为有时会导致某个AZ中的较新实例在另一个AZ中的较旧实例之前被终止

需求:

有些客户希望始终一致地终止最旧的实例,不论AZ分布如何。

解决方案:

为了满足这一需求,本文提供了一个自定义Lambda函数来实施特定的终止策略。该函数利用EC2 DescribeInstances API准确识别ASG中最旧的实例。通过CloudFormation模板,该解决方案的部署得以简化,自动设置Lambda函数和必要的IAM权限。

CloudFormation YAML 文件内容 :

AWSTemplateFormatVersion: '2010-09-09'
Resources:
  LambdaExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: LambdaExecutionPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'
              - Effect: Allow
                Action:
                  - 'ec2:DescribeInstances'
                Resource: '*'
  MyLambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import boto3
          import logging
          logger = logging.getLogger()
          logger.setLevel(logging.INFO)
          ec2 = boto3.client('ec2')
          def lambda_handler(event, context):
              logger.info("Received event: " + str(event))
              instance_ids = [instance['InstanceId'] for instance in event.get('Instances', [])]
              logger.info("Instance IDs: " + str(instance_ids))
              if instance_ids:
                  descriptions = ec2.describe_instances(InstanceIds=instance_ids)
                  instances = [i for r in descriptions['Reservations'] for i in r['Instances']]
                  oldest_instance = sorted(instances, key=lambda x: x['LaunchTime'])[0]['InstanceId']
                  logger.info("Oldest instance ID: " + oldest_instance)
                  return {'InstanceIDs': [oldest_instance]}
              else:
                  logger.info("No instances to process.")
                  return {'InstanceIDs': []}
      Runtime: python3.9
      Timeout: 30
  LambdaInvokePermission:
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      FunctionName: !GetAtt MyLambdaFunction.Arn
      Principal: !Sub 'arn:aws:iam::${AWS::AccountId}:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling'

部署CloudFormation模板的步骤:

  1. 保存模板:
  • 将上述YAML内容保存为文件,比如 terminate_oldest_template.yaml 的文件。
  1. 访问AWS管理控制台:
  • 登录您的AWS账户,并导航至AWS CloudFormation控制台。
  1. 创建新堆栈:
  • 选择“创建堆栈” -> “使用新资源(标准)”。
  • 选择“上传模板文件”,点击“选择文件”,并上传 terminate_oldest_template.yaml 文件。
  • 点击“下一步”。
  1. 指定堆栈详细信息:
  • 输入堆栈名称,例如 ASGTerminateOldestInstanceStack。
  • 点击“下一步”。
  1. 配置堆栈选项:
  • 配置任何必要的选项,如标签或权限。对于大多数情况,默认选项已足够。
  • 点击“下一步”。
  1. 检查并启动:
  • 检查所有设置以确保它们是正确的。
  • 确认AWS CloudFormation可能会创建IAM资源,然后点击“创建堆栈”。
  1. 查看部署:
  • 在CloudFormation控制台上查看堆栈的创建。等待状态变为“CREATE_COMPLETE”。

更改ASG终止策略来使用新的Lambda函数:

  • 访问 https://console.aws.amazon.com/ec2/,打开 Amazon EC2 控制台,然后从导航窗格中选择 Auto Scaling Groups(Auto Scaling 组)。

  • 选中并点击 Auto Scaling 组。

  • 在 Details(详细信息)选项卡上,选择 Advanced configurations(高级配置)、Edit(编辑)。

  • 对于 Termination policies(终止策略),选择 Custom termination policy(自定义终止策略),然后选择刚创建完成的 Lambda 函数。如果您已经为 Lambda 函数创建了版本和别名,则可以从 Version/Alias(版本/别名)下拉列表选择版本或别名。要使用您的 Lambda 函数的未发布版本,请保留 Version/Alias(版本/别名)设置为默认值。 参考此篇文档了解更多

参考资料:

预定义的终止政策

更改 Auto Scaling 组的终止策略

profile pictureAWS
支持工程师
Tim
已​发布 1 个月前1595 查看次数