7

我必须在 AWS 自动缩放缩减事件期间采取某些措施。ec2 实例应该能够将一些日志和报告保存到 S3 存储桶。这可能需要 5 到 15 分钟。

我已经有一个在终止时调用的脚本:

ln -s /etc/ec2-termination /etc/rc0.d/S01ec2-termination

然而,脚本在 5 分钟内突然结束。我正在考虑利用 AWS LifeCycle 挂钩来延长 EC2 的生命周期。文档并不清楚以类似于用户数据脚本的方式调用脚本。

有多种方法可以使用 AWS lambda 或 SNS 来接收通知。这可以潜在地用于通知 ec2。

但是,我想知道这个问题是否有更简单的解决方案。有没有办法注册一个带有生命周期钩子的脚本,该钩子在缩减事件中被调用。

4

5 回答 5

11

不。

实例被终止的事实在 AWS 基础设施中进行管理。Auto Scaling 无法“进入”EC2 实例以触发任何事情。

相反,您需要在实例上编写一些代码来检查实例是否处于终止状态,然后采取适当的措施。

一个例子可能是:

  • Lifecycle Hook通过 Amazon SNS发送通知
  • Amazon SNS触发 AWS Lambda 函数
  • Lambda 函数可以向实例添加标签(例如 Terminating = Yes)
  • EC2 实例上的脚本每 15 秒触发一次,以检查与 EC2 实例(在其上运行)关联的标签。如果它找到标签,它会触发关闭过程。

(注意在关机过程中脚本不会再次触发,否则它可能会尝试每 15 秒执行一次关机过程!)

或者,将关闭信息存储在 Systems Manager Parameter Store 或数据库中,但使用标签似乎具有很好的可扩展性!

更新后的版本:

感谢 raevilman 的想法:

  • Lifecycle Hook通过 Amazon SNS发送通知
  • Amazon SNS触发 AWS Lambda 函数
  • Lambda 函数调用AWS Systems Manager Run Command以触发实例上的代码

简单多了!

于 2018-05-09T05:54:42.360 回答
6

是的,您可以使用 AWS 系统管理器在终止的 EC2 实例上运行 shell 脚本。

  1. 为您的 Autoscaling 组配置生命周期挂钩。您可以从EC2 控制台或 CLI 执行此操作:

    aws autoscaling put-lifecycle-hook
    --lifecycle-hook-name my-lifecycle-hook
    --auto-scaling-group-name My_AutoScalingGroup
    --lifecycle-transition autoscaling:EC2_INSTANCE_TERMINATING
    --default-result CONTINUE
    --region us-east- 2

根据脚本运行所需的持续时间设置 Heartbeat 超时值。现在,当您的 ASG 缩减时,您的实例将进入 Terminate:Wait 状态,在此期间您的脚本将运行。

  1. 设置在实例更改为 Terminating:Wait 状态时触发的 CloudWatch 事件,它针对在您的实例上执行 shell 脚本的系统管理器运行命令。使用控制台

替代解决方案:当实例更改为 Terminating:Wait 状态时,您的生命周期挂钩会向 SQS 发送带有 Instance-ID 的消息。SQS 在接收到消息时触发 Lambda 函数,该函数将运行命令发送到系统管理器以在您的终止实例上执行 shell 脚本。

参考文献: 1 2 3

于 2020-07-21T20:56:31.910 回答
3

这是基于本文的使用 Lifecycle Hooks、Automation 和 Run Command 的解决方案:

Resources:
  MyTerminationHook:
    Type: AWS::AutoScaling::LifecycleHook
    Properties:
      AutoScalingGroupName: !Ref MyAutoScalingGroup
      DefaultResult: CONTINUE
      HeartbeatTimeout: 900
      LifecycleTransition: autoscaling:EC2_INSTANCE_TERMINATING

  MyTerminationDocument:
    Type: AWS::SSM::Document
    Properties:
      DocumentType: Automation
      Content:
        description: 'Run command before terminating instance'
        schemaVersion: '0.3'
        assumeRole: !GetAtt MyTerminationDocumentRole.Arn
        parameters:
          instanceId:
            type: String
        mainSteps:
          - name: RunCommand
            action: aws:runCommand
            inputs:
              DocumentName: AWS-RunShellScript
              InstanceIds:
                - '{{ instanceId }}'
              TimeoutSeconds: 60
              Parameters:
                commands: /etc/my-termination-script.sh
                executionTimeout: '900'
          - name: TerminateInstance
            action: aws:executeAwsApi
            inputs:
              Api: CompleteLifecycleAction
              AutoScalingGroupName: !Ref MyAutoScalingGroup
              InstanceId: '{{ instanceId }}'
              LifecycleActionResult: CONTINUE
              LifecycleHookName: !Ref MyTerminationHook
              Service: autoscaling

  MyTerminationRule:
    Type: AWS::Events::Rule
    Properties:
      EventPattern:
        source:
          - aws.autoscaling
        detail-type:
          - EC2 Instance-terminate Lifecycle Action
        detail:
          AutoScalingGroupName:
            - !Ref MyAutoScalingGroup
      Targets:
        - Id: my-termination-document
          Arn: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${MyTerminationDocument}:$DEFAULT'
          RoleArn: !GetAtt MyTerminationRuleRole.Arn
          InputTransformer:
            InputPathsMap:
              instanceId: '$.detail.EC2InstanceId'
            InputTemplate: '{"instanceId":[<instanceId>]}'

  MyTerminationRuleRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: start-automation
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - ssm:StartAutomationExecution
                Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/${MyTerminationDocument}:$DEFAULT'

  MyTerminationDocumentRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ssm.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: run-command-and-complete-lifecycle
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - autoscaling:CompleteLifecycleAction
                Resource: !Sub 'arn:aws:autoscaling:${AWS::Region}:${AWS::AccountId}:autoScalingGroup:*:autoScalingGroupName/${MyAutoScalingGroup}'
              - Effect: Allow
                Action:
                  - ssm:DescribeInstanceInformation
                  - ssm:ListCommands
                  - ssm:ListCommandInvocations
                Resource: '*'
              - Effect: Allow
                Action:
                  - ssm:SendCommand
                Resource: 'arn:aws:ssm:*::document/AWS-RunShellScript'
              - Effect: Allow
                Action:
                  - ssm:SendCommand
                Resource: !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/*'
于 2020-12-07T08:28:56.967 回答
1

根据您想要实现的目标,使用这种方法您只需要两件事而且更简单):

  1. Lifecycle Hook 向 SQS 发送通知
  2. 应用程序读取 SQS 并执行操作
于 2019-06-03T08:24:14.637 回答
0

只是对我之前评论的更正。如果实例由于自动缩放事件而终止,则 SSM 运行命令将对 Autoscaling 组中的实例起作用,而不是如果您手动终止实例。

于 2021-05-26T19:40:59.787 回答