【问题标题】:Invoke a script on EC2 termination在 EC2 终止时调用脚本
【发布时间】:2018-05-09 05:21:20
【问题描述】:

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

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

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

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

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

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

【问题讨论】:

  • 为什么不运行一个 cron 作业以定期收集日志以节省关机时间#Sweet :)
  • cron 作业是一种极好的替代方法。如果您使用自动缩放,最好设计系统,使其不依赖于长期可用的特定实例。

标签: amazon-web-services amazon-ec2 lifecycle-hook


【解决方案1】:

没有。

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

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

一个例子可能是:

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

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

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

更新版本:

感谢 raevilman 的创意:

  • 生命周期挂钩通过 Amazon SNS 发送通知
  • Amazon SNS 触发 AWS Lambda 函数
  • Lambda 函数调用AWS Systems Manager Run Command 来触发实例上的代码

简单多了!

【讨论】:

  • 而不是让脚本每 15 秒运行一次来​​检查标签....步骤 2 中的 lambda 可以将 AWS SSM 命令发送到 EC2 :) 这样你的“小心点让脚本运行在系统关闭时再次覆盖“HIH
【解决方案2】:

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

  1. 为您的 Autoscaling 组配置生命周期挂钩。您可以通过 EC2 console 或 CLI 执行此操作:

    aws 自动缩放 put-lifecycle-hook
    --lifecycle-hook-name 我的生命周期-hook
    --auto-scaling-group-name My_AutoScalingGroup
    --lifecycle-transition 自动缩放:EC2_INSTANCE_TERMINATING
    --default-result 继续
    --region us-east-2

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

  1. 设置一个 CloudWatch 事件,该事件在实例更改为 Terminating:Wait 状态时触发,它以在您的实例上执行 shell 脚本的系统管理器运行命令为目标。使用console

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

参考资料: 1 2 3

【讨论】:

  • 我们试过这个,但我们无法弄清楚如何让 cloudwatch 事件将实例 ID 传递给“SSM 运行命令”。对如何做到这一点有任何见解吗?
  • 是的,这里也一样。我不确定如何实际定位 那个 特定实例
  • @bpeikes 我想通了。在this post 中查看我的答案。本质上,您需要从 EventBridge 调用 Lambda 函数,而不是直接调用 SSM 命令。然后在 Lambda 中,您可以解析事件数据 (json),提取 instanceId,然后使用 ssm api 将命令发送到该实例。
【解决方案3】:

这是一个使用 Lifecycle Hooks、Automation 和 Run Command 的解决方案,基于 this article

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/*'

【讨论】:

    【解决方案4】:

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

    1. 生命周期挂钩向 SQS 发送通知
    2. 应用读取 SQS 并执行操作

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 你有这个来源吗?很高兴能 100% 确定地知道。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-01
      • 1970-01-01
      • 2011-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多