ASG의 EC2 인스턴스 부분을 더 빠르게 가동 - 미션 임파서블? 아니면 안될까요?!

우리 모두는 몇 초 만에 실행되는 경량 도커 이미지 또는 번개처럼 빠른 시간 내에 트리거되는 Lamba 기능에서 실행되는 이러한 모든 서버리스 기회에 대해 알고 있습니다.
그러나 ECS Fargate, Lambda, EKS 등과 같은 모든 서버리스 솔루션을 선호하고 팬이라고 하더라도 이것이 만병통치약이 될 수 없으며 서버리스로 모든 경우를 해결할 수 없다는 것은 분명합니다.
모든 기술과 마찬가지로 EC2도 예외가 아니며 장점과 병목 현상으로 간주할 사항이 있습니다.
본질적으로 EC2는 전체 크기의 운영 체제가 있고 부팅 시간 요소에서 벗어날 수 없는 가상 머신을 나타냅니다. 그 동안 AWS는 고객의 요구 사항에 귀를 기울이는 선두 주자입니다.
이것이 EBS가 등장한 지 10년이 지난 2019년에 EBS Fast Snapshot Restore(FSR)라는 기능을 선보인 이유입니다. 이 기능을 사용하면 스냅샷을 사용하고 최대 16TiB 공간과 64K IOPS로 새로운 EBS 볼륨을 생성할 수 있습니다.
이미 알고 계시겠지만 이 기능의 주요 이점은 EC2 부팅 속도를 높이는 것입니다.

사용 사례



비용 효율적인 방식으로 AutoScaling 그룹의 새 인스턴스 부분의 부팅 프로세스 속도를 높입니다.

의문



FSR 기능의 이점을 누리면서 동시에 잠재적인 추가 비용을 피할 수 있습니까?

해결책



빠른 스냅샷 복원 기능은 무료가 아니므로 비즈니스를 지원하는 다른 모든 서비스와 마찬가지로 주의해서 사용을 처리해야 합니다. 그러기 위해서는 먼저 특정 가용 영역의 스냅샷에 대해 Fast Snapshot Restore가 활성화된 시간당 0.75 USD가 부과된다는 사실을 알아야 합니다. 두 번째로 알아야 할 것은 이 기능의 이점을 누릴 수 있는 시기이며 대답은 간단합니다. 부팅 시간 동안만(일단 인스턴스가 작동하면 다음에 필요할 때까지 비활성화할 수 있음). 지금까지는 괜찮았지만 사전 통지 없이 중단이 발생하고 우리는 준비해야 합니다. 이것이 일부 자동화가 이 상황에서 우리에게 도움이 되는 이유입니다. ASG를 사용하는 경우 수명 주기 후크, 즉 EC2 인스턴스의 시작/종료를 중지하고 종료 또는 시작을 허용하기 전에 일부 작업을 트리거할 수 있는 기회가 있다는 것을 가장 잘 알고 있을 것입니다.
다음은 상황을 명확하게 보여주는 작은 다이어그램입니다.



Step Function을 배포하기 위한 CloudForamtion 템플릿의 설정은 다음과 같습니다.

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Enable/Disable FRS on newly launched instance in AutoScaling Group

Parameters:

  Asg:
    Description: 'Source ASG from where to get an instance Id to create the new AMI'
    Type: String
    Default: MyASG

  LambdaManageFrsZipLocation:
    Description: 'Name of the Python Lambda function to manage AMIs zip file'
    Type: String
    Default: 'FRS.zip'

  LambdaStartStepFunctionZipLocation:
    Description: 'Name of the Python Lambda function to start step function zip file'
    Type: String
    Default: 'StartStepFunction.zip'

  LambdaCompleteLifecycleHookZipLocation:
    Description: 'Name of the Python Lambda function to complete lifecycle hook zip file'
    Type: String
    Default: 'CompleteLifecycleHook.zip'

  Region:
    Description: 'Operational Region'
    Type: String
    Default: 'us-east-1'

  Environment:
    Description: 'Environment Name'
    Type: String
    Default: 'Prod'

  ActivateLifecycleWhenLaunchOrch:
    Description: 'Has the FRS to be activated when the instance is launching (Y/N) ?'
    Type: String
    Default: Y
    AllowedValues:
      - Y
      - N

#---------------------------------------------------------------------------------------------------------------------------------------------------------
Conditions:
  ActivateLifecycleConditionStart: !Equals [!Ref 'ActivateLifecycleWhenLaunchOrch', 'Y']
#---------------------------------------------------------------------------------------------------------------------------------------------------------

Resources:
  myStepFunctionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: !Sub 'StepFunctionRole-${Environment}-${AWS::Region}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: states.amazonaws.com
            Action: 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: ManageAmiStepFunctionPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: VisualEditor0
                Effect: Allow
                Action:
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 'arn:aws:logs:*:*:*'
              - Sid: VisualEditor1
                Effect: Allow
                Action:
                  - 'lambda:InvokeFunction'
                Resource: '*'
              - Sid: SomeNewSid
                Effect: Allow
                Action: 'logs:CreateLogGroup'
                Resource: '*'

  myLambdaManageAmiRole:
    Type: AWS::IAM::Role
    Properties:
      Description: 'Manage AMI'
      MaxSessionDuration: 3600
      Path: '/service-role/'
      RoleName: !Sub 'ManageFrsLambdaRole_${Environment}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Policies:
        - PolicyName: allowLogging
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
              Resource: '*'
        - PolicyName: allowEC2
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - ec2:DescribeImages
              - ec2:CreateTags
              - ec2:DescribeFastSnapshotRestores
              - ec2:DisableFastSnapshotRestores
              - ec2:EnableFastSnapshotRestores
              Resource: '*'
        - PolicyName: allowDescribeAutoScaling
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - autoscaling:DescribeAutoScalingGroups
              Resource: '*'
        - PolicyName: allowIamPassRole
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - iam:PassRole
              - iam:ListAccessKeys
              Resource: !Sub "arn:aws:iam::${AWS::AccountId}:role/*"
        - PolicyName: allowKMS
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
              - kms:CreateGrant
              - kms:DescribeKey*
              - kms:ListKeys
              - kms:ListAliases
              Resource: '*'
        - PolicyName: allowSSMCommands
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - ssm:SendCommand
              - ssm:GetCommandInvocation
              Resource: '*'

  myLambdatoStartStepFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      Description: 'Start Step Function'
      MaxSessionDuration: 3600
      Path: '/service-role/'
      RoleName: !Sub 'StartStepFunctionLambdaRole_${Environment}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Policies:
        - PolicyName: allowLogging
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
              Resource: '*'
        - PolicyName: allowStates
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - states:StartExecution
              Resource: 
              - !GetAtt myFastRestoreStepFunction.Arn
        - PolicyName: allowSNS
          PolicyDocument:
            Version: 2012-10-17
            Statement:
            - Effect: Allow
              Resource: "*"
              Action:
              - sns:Publish
        - PolicyName: allowASG
          PolicyDocument:
            Version: 2012-10-17
            Statement:
            - Effect: Allow
              Resource: "*"
              Action:
              - autoscaling:CompleteLifecycleAction

  myLifecycleHookRole:
    Type: "AWS::IAM::Role"
    Properties:
        AssumeRolePolicyDocument:
            Version: "2012-10-17"
            Statement:
              -
                Effect: "Allow"
                Action:
                  - "sts:AssumeRole"
                Principal:
                    Service:
                      - "autoscaling.amazonaws.com"
        Path: /
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AutoScalingNotificationAccessRole

  myLambdatoCompleteLifecycleHookRole:
    Type: AWS::IAM::Role
    Properties:
      Description: 'Complete Lifecycle Hook'
      MaxSessionDuration: 3600
      Path: '/service-role/'
      RoleName: !Sub 'CompleteLifecycleHookLambdaRole_${Environment}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Policies:
        - PolicyName: allowLogging
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
              Resource: '*'

        - PolicyName: allowASG
          PolicyDocument:
            Version: 2012-10-17
            Statement:
            - Effect: Allow
              Resource: "*"
              Action:
              - autoscaling:CompleteLifecycleAction

  myLambdatoCompleteLifecycleHook:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Sub 'cft-templates.${AWS::AccountId}.${AWS::Region}'
        S3Key: !Ref LambdaCompleteLifecycleHookZipLocation
      Description: 'Complete Lifecycle Hook'
      FunctionName: !Sub 'CompleteLifecycleHookLambda_${Environment}'
      Handler: CompleteLifecycleHook.lambda_handler
      Role: !GetAtt myLambdatoCompleteLifecycleHookRole.Arn
      Runtime: 'python3.8'
      Timeout: 300

  myFastRestoreStepFunction:
    Type: AWS::Serverless::StateMachine
    Properties:
      Name: !Sub 'ManageFastRestoreStepFunction_${Environment}'
      Type: STANDARD
      Role: !GetAtt myStepFunctionRole.Arn
      Definition:
        #Comment: Step Function to Enable FastRestore
        StartAt: Search for EC2 Id in ASG #Started by Lifecycle Hook 1 ?
        States:

          Search for EC2 Id in ASG:
            Type: Task
            OutputPath: '$.Payload'
            Resource: arn:aws:states:::lambda:invoke
            Parameters:
              FunctionName: !GetAtt myLambdatoManageFrs.Arn
              Payload:
                ASGName.$: '$.ASGName'
                lifeCycleHook.$: '$.lifeCycleHook'
                instance.$: '$.instance'
                region.$: '$.region'
                status.$: '$.status'
                AMIid.$: '$.AMIid'
                cmd: 'getASGInstanceId'
            Next: Get AMI ID

          Get AMI ID:
            Type: Task
            OutputPath: '$.Payload'
            Resource: arn:aws:states:::lambda:invoke
            Parameters:
              FunctionName: !GetAtt myLambdatoManageFrs.Arn
              Payload:
                ASGName.$: '$.ASGName'
                lifeCycleHook.$: '$.lifeCycleHook'
                instance.$: '$.instance'
                region.$: '$.region'
                status.$: '$.status'
                AMIid.$: '$.AMIid'
                cmd: 'getInstanceImageId'
            Next: Enable FastSnapshotRestores

          Enable FastSnapshotRestores:
            Type: Task
            OutputPath: '$.Payload'
            Resource: arn:aws:states:::lambda:invoke
            Parameters:
              FunctionName: !GetAtt myLambdatoManageFrs.Arn
              Payload:
                ASGName.$: '$.ASGName'
                lifeCycleHook.$: '$.lifeCycleHook'
                instance.$: '$.instance'
                region.$: '$.region'
                status.$: '$.status'
                AMIid.$: '$.AMIid'
                cmd: 'enableFastRestore'
            Next: Check FastRestore

          Test FastRestore:
            Type: Choice
            Choices:
            - Variable: '$.status'
              StringEquals: enabled
              Next: Parallel
            - Not:
                Variable: '$.status'
                StringEquals: enabled
              Next: Wait 20s Fast

          Wait 20s Fast:
            Type: Wait
            Seconds: 20
            Next: Check FastRestore

          Check FastRestore:
            Type: Task
            OutputPath: '$.Payload'
            Resource: arn:aws:states:::lambda:invoke
            Parameters:
              FunctionName: !GetAtt myLambdatoManageFrs.Arn
              Payload:
                ASGName.$: '$.ASGName'
                lifeCycleHook.$: '$.lifeCycleHook'
                instance.$: '$.instance'
                region.$: '$.region'
                status.$: '$.status'
                AMIid.$: '$.AMIid'
                cmd: 'showFastRestore'
            Next: Test FastRestore
          Parallel:
            Type: Parallel
            Branches:
              [
              {
              "StartAt": "Wait for Disable FastRestore",
              "States": {
                "Wait for Disable FastRestore": {
                  "Seconds": 3000,
                  "Type": "Wait",
                  "Next": "Disable FastSnapshotRestores"
                },
                "Disable FastSnapshotRestores": {
                  "Next": "success",
                  "OutputPath": "$.Payload",
                  "Parameters": {
                    "FunctionName": !GetAtt myLambdatoManageFrs.Arn,
                    "Payload": {
                      "AMIid.$": "$.AMIid",
                      "ASGName.$": "$.ASGName",
                      "cmd": "disableFastRestore",
                      "instance.$": "$.instance",
                      "lifeCycleHook.$": "$.lifeCycleHook",
                      "region.$": "$.region",
                      "status.$": "$.status"

                    }
                  },
                  "Resource": "arn:aws:states:::lambda:invoke",
                  "Type": "Task"
                },
                "success": {
                  "Type": "Pass",
                  "End": true
                }
              }
              },
              {
              "StartAt": "Complete Lifecycle Hook",
              "States": {
                "Complete Lifecycle Hook": {
                  "OutputPath": "$.Payload",
                  "Parameters": {
                    "FunctionName": !GetAtt myLambdatoCompleteLifecycleHook.Arn,
                    "Payload": {
                      "AMIid": "null",
                      "ASGName.$": "$.ASGName",
                      "cmd": "null",
                      "instance.$": "$.instance",
                      "lifeCycleHook.$": "$.lifeCycleHook",
                      "region": "null",
                      "status": "null"
                    }
                  },
                  "Resource": "arn:aws:states:::lambda:invoke",
                  "Type": "Task",
                  "Catch": [
                    {
                      "ErrorEquals": [
                        "States.ALL"
                      ],
                      "Next": "handle failure",
                      "ResultPath": "$.error"
                    }
                  ],
                  "End": true
                },
                "handle failure": {
                  "Type": "Pass",
                  "End": true
                }
              }
              }
              ]
            "End": true


  #Lambda to trigger the Step Function dedicated to enable FastRestore Snapshot on new EC2 instance launch in the ASG
  myLambdatoStartFastRestoreStepFunction:
    Type: AWS::Lambda::Function
    Properties:
      Environment:
        Variables:
          STATE_MACHINE_ARN: !GetAtt myFastRestoreStepFunction.Arn
      Code:
        S3Bucket: !Sub 'cft-templates.${AWS::AccountId}.${AWS::Region}'
        S3Key: !Ref LambdaStartStepFunctionZipLocation
      Description: 'Launch Step Function handling FRS enable/disable on EC2 launch'
      FunctionName: !Sub 'StartFastRestoreStepFunctionLambda_${Environment}'
      Handler: StartStepFunction.lambda_handler
      Role: !GetAtt myLambdatoStartStepFunctionRole.Arn
      Runtime: 'python3.8'
      Timeout: 300

  # Lifecycle hook to trigger the Enable/Disable of FRS when instance is launched on the Orchestrator ASG
  myStartLifecycleHookTopic:
    Type: AWS::SNS::Topic

  myStartLifecycleHookSubscription:
    Type: AWS::SNS::Subscription
    Properties:
      Endpoint: !GetAtt myLambdatoStartFastRestoreStepFunction.Arn
      Protocol: "lambda"
      TopicArn: !Ref myStartLifecycleHookTopic

  myStartPermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: "lambda:InvokeFunction"
      FunctionName: !GetAtt myLambdatoStartFastRestoreStepFunction.Arn
      Principal: sns.amazonaws.com
      SourceArn: !Ref myStartLifecycleHookTopic

  myStartLifecycleHookASG:
    Type: AWS::AutoScaling::LifecycleHook
    Condition: ActivateLifecycleConditionStart
    Properties:
      AutoScalingGroupName: !Ref Asg
      LifecycleTransition: "autoscaling:EC2_INSTANCE_LAUNCHING"
      DefaultResult: CONTINUE
      HeartbeatTimeout: 600
      NotificationMetadata: !Sub |-
        {
          "lifeCycleHook": "null",
          "ASGName": "${Asg}",
          "instance": "null",
          "region": "${Region}",
          "status": "null",
          "AMIid": "null",
          "cmd": "null"
        }
      NotificationTargetARN:
        Ref: myStartLifecycleHookTopic
      RoleARN: !GetAtt myLifecycleHookRole.Arn

  myLambdatoManageFrs:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Sub 'cft-templates.${AWS::AccountId}.${AWS::Region}'
        S3Key: !Ref LambdaManageFrsZipLocation
      Description: 'Manage Fast Restore Snapshot'
      FunctionName: !Sub 'ManageFRS_${Environment}'
      Handler: FRS.lambda_handler
      Role: !GetAtt myLambdaManageFrsRole.Arn
      Runtime: 'python3.8'
      Timeout: 300

  myLambdaManageFrsRole:
    Type: AWS::IAM::Role
    Properties:
      Description: 'Manage FRS'
      MaxSessionDuration: 3600
      Path: '/service-role/'
      RoleName: !Sub 'ManageFRS_${Environment}'
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      Policies:
        - PolicyName: allowLogging
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
              Resource: '*'
        - PolicyName: allowEC2
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - ec2:CreateTags
              - ec2:Describe*
              - ec2:DisableFastSnapshotRestores
              - ec2:EnableFastSnapshotRestores
              Resource: '*'
        - PolicyName: allowDescribeAutoScaling
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - autoscaling:DescribeAutoScalingGroups
              Resource: '*'
        - PolicyName: allowIamPassRole
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
              - iam:PassRole
              - iam:ListAccessKeys
              Resource: !Sub "arn:aws:iam::${AWS::AccountId}:role/*"



논리를 다루기 위해 여러 Lambda 함수가 있습니다.

FRS 람다:

import boto3
from botocore.config import Config
import json
from datetime import tzinfo, timedelta, datetime
import time
import sys
import os

# --------------------------------------------------------------------------------------------------------------------------------
# To display debug messages (True or False)
DEBUG = True

def message(msg):
    if DEBUG:
        print(msg)
    return

def error(err, msg ):
    raise Exception (f"{msg} --- err = {err}")

def getASGInstanceId(asgClient, asgName):
    try:
        message("---- getInstanceId")

        # get object for the ASG we're going to update, filter by name of target ASG
        response = asgClient.describe_auto_scaling_groups(AutoScalingGroupNames=[asgName])

        if not response['AutoScalingGroups']:
            err = f"## No such ASG '{asgName}'"
            message(err)
            raise RuntimeError(err)

        # get InstanceID in current ASG that we'll use to model new Launch Configuration after
        instanceId = response.get('AutoScalingGroups')[0]['Instances'][-1]['InstanceId']

    except Exception as e:
        message(f"==== e = {e}")
        return(error(e, f"## Failed to get ASG Instance Id of ASG '{asgName}'"))

    message(f"InstanceId = {instanceId}")
    return instanceId
def getInstanceImageId(instanceId):
    ec2_client = boto3.client('ec2')
    ec2_response = ec2_client.describe_instances(
    InstanceIds = [instanceId]
      )
    for instances in ec2_response['Reservations']:
        for image in instances['Instances']:
            print(image['ImageId'])
            AMIid = image['ImageId']
    return AMIid
def enableFastRestore(AMIid,asgName):
    ec2 = boto3.client('ec2')
    ec2response = ec2.describe_images(
        ImageIds=[
            AMIid
        ],
    )

    asg  = boto3.client('autoscaling')
    # You may need to edit the filter here for your use case
    for i  in range(5):
        if ec2response['Images'][0]['BlockDeviceMappings'][i]['Ebs']['VolumeSize'] < 40:
            snapshotid=ec2response['Images'][0]['BlockDeviceMappings'][i]['Ebs']['SnapshotId']
    print(snapshotid)
    asgresponse = asg.describe_auto_scaling_groups(
                AutoScalingGroupNames=[
                            asgName,
                                ]
                        )

    print(asgresponse['AutoScalingGroups'][0]['AvailabilityZones'][0])
    az=asgresponse['AutoScalingGroups'][0]['AvailabilityZones'][0]
    try:
        fsrresponse = ec2.enable_fast_snapshot_restores(
                   AvailabilityZones=[
                         az,
                   ],
                   SourceSnapshotIds=[
                         snapshotid,
                   ]
        )
    except Exception as e:
        message(f"==== e = {e}")
        return(error(e, f"## Failed to Enable Fast Restore "))
    return fsrresponse

# deactivate FastRestore Snapshot

def disableFastRestore(AMIid,asgName):
    ec2 = boto3.client('ec2')
    ec2response = ec2.describe_images(
        ImageIds=[
            AMIid
        ],
    )

    asg  = boto3.client('autoscaling')
    # You may need to edit the filter here for your use case
    for i  in range(5):
        if ec2response['Images'][0]['BlockDeviceMappings'][i]['Ebs']['VolumeSize'] < 40:
            snapshotid=ec2response['Images'][0]['BlockDeviceMappings'][i]['Ebs']['SnapshotId']
    print(snapshotid)
    asgresponse = asg.describe_auto_scaling_groups(
                AutoScalingGroupNames=[
                            asgName,
                                ]
                        )

    print(asgresponse['AutoScalingGroups'][0]['AvailabilityZones'][0])
    az=asgresponse['AutoScalingGroups'][0]['AvailabilityZones'][0]
    try:
        fsrresponse = ec2.disable_fast_snapshot_restores(
                   AvailabilityZones=[
                         az,
                   ],
                   SourceSnapshotIds=[
                         snapshotid,
                   ]
        )
    except Exception as e:
        message(f"==== e = {e}")
        return(error(e, f"## Failed to Disable Fast Restore "))
    return fsrresponse


def showFastRestore(AMIid,asgName):
    ec2 = boto3.client('ec2')
    ec2response = ec2.describe_images(
        ImageIds=[
            AMIid
        ],
    )

    asg  = boto3.client('autoscaling')
    # You may need to edit filter here for your use case
    for i  in range(5):
        if ec2response['Images'][0]['BlockDeviceMappings'][i]['Ebs']['VolumeSize'] < 40:
            snapshotid=ec2response['Images'][0]['BlockDeviceMappings'][i]['Ebs']['SnapshotId']
    print(snapshotid)
    asgresponse = asg.describe_auto_scaling_groups(
                AutoScalingGroupNames=[
                            asgName,
                                ]
                        )

    print(asgresponse['AutoScalingGroups'][0]['AvailabilityZones'][0])
    az=asgresponse['AutoScalingGroups'][0]['AvailabilityZones'][0]
    try:
        fsrresponse = ec2.describe_fast_snapshot_restores(
            Filters=[
               {
                'Name': 'snapshot-id',
                'Values': [
                             snapshotid,
                       ]
                    },
            ]
        )
    except Exception as e:
        message(f"==== e = {e}")
        return(error(e, f"## Failed to Disable Fast Restore "))
    fsrstate=fsrresponse['FastSnapshotRestores'][0]['State']
    return fsrstate

def lambda_handler(event, context):
    message("Received event: " + json.dumps(event, indent=2))
#----------------
    lifeCycleHook = event['lifeCycleHook']
    asgName = event['ASGName']
    instance = event['instance']
    status = event['status']
    region_name=event['region']
    status=event['status']
    AMIid=event['AMIid']
    cmd = event['cmd']

#----------------
    autoscalingClient = boto3.client('autoscaling')

    ec2Client   = boto3.client('ec2', region_name)

    ec2Resource   = boto3.resource('ec2', region_name)

    ssmClient   = boto3.client('ssm',  region_name)

#----------------

    message(f"---- CMD = {cmd}")

    if cmd == 'getASGInstanceId':
        message("---- Get instance Id from ASG")

        instance = getASGInstanceId(autoscalingClient, asgName)
        AMIid = getInstanceImageId(instance)
    elif cmd == 'getInstanceImageId':
        instance = getASGInstanceId(autoscalingClient, asgName)
        message("---- Get Instance Image Id on instance: " + instance)
        AMIid = getInstanceImageId(instance)
    elif cmd == 'enableFastRestore':
        message("---- Enable Fast Restore")
        instance = getASGInstanceId(autoscalingClient, asgName)
        AMIid = getInstanceImageId(instance)
        response = enableFastRestore(AMIid,asgName)
    elif cmd == 'disableFastRestore':
        instance = getASGInstanceId(autoscalingClient, asgName)
        message("---- Disable Fast Restore")
        AMIid = getInstanceImageId(instance)
        response = disableFastRestore(AMIid,asgName)
    elif cmd == 'showFastRestore':
        message("---- Show Fast Restore")
        instance = getASGInstanceId(autoscalingClient, asgName)
        AMIid = getInstanceImageId(instance)
        status = showFastRestore(AMIid,asgName)

    else:
        return(error(e, f"Command '{cmd}' is not recognized or planned to be managed" ))

    result = {"lifeCycleHook": lifeCycleHook, "ASGName": asgName, "instance": instance,  "region": region_name, "status": status,  "AMIid": AMIid, "cmd": cmd}
    message("##### RETURN result :  " + json.dumps(result, indent=2))
    return result


전체 수명 주기 후크 Lambda:

import boto3
from botocore.exceptions import ClientError
import os
import json


asgClient = boto3.client('autoscaling')

def lambda_handler(event, context):
    print('The Lambda function is starting.')
    print("Received event: " + json.dumps(event, indent=2))

    autoScalingGroup = event['ASGName']
    instanceId = event['instance']
    lifeCycleHook = event['lifeCycleHook']

    actionResult = "CONTINUE"

    response = asgClient.complete_lifecycle_action(
        LifecycleHookName = lifeCycleHook,
        AutoScalingGroupName = autoScalingGroup,
        LifecycleActionResult = actionResult,
        InstanceId = instanceId
    )

    print(f"Complete lifecycle hook response : {response}")
    return



단계 함수 Lambda 시작:

import boto3
from datetime import tzinfo, timedelta, datetime
from botocore.exceptions import ClientError
import os
import json
import ast

STATE_MACHINE_ARN = os.environ.get('STATE_MACHINE_ARN')

stepFnClient = boto3.client('stepfunctions')

def lambda_handler(event, context):
    print('The Lambda function is starting.')
    print("Received event: " + json.dumps(event, indent=2))

    datename = datetime.now().strftime('%Y_%m_%d_%HH%M')
    EXECUTION_NAME = 'Life_Cycle_Hook_Start_' + datename
    message = event['Records'][0]['Sns']['Message']
    msgJson = json.loads(message)
    instanceId=msgJson["EC2InstanceId"]
    lifecycleHookName=msgJson["LifecycleHookName"]
    lifecycleActionToken=msgJson["LifecycleActionToken"]
    autoScalingGroupName=msgJson["AutoScalingGroupName"]
    notificationMetadata=msgJson["NotificationMetadata"]
    notificationMetadataDict = json.loads(notificationMetadata)

    print(f"----- NotificationMetadataDict = {notificationMetadataDict}")
    notificationMetadataDict["lifeCycleHook"] = lifecycleHookName
    notificationMetadataDict["instance"] = instanceId
    notificationMetadataDict["ASGName"] = autoScalingGroupName

    print(f"----- NotificationMetadataDict = {notificationMetadataDict}")
    notificationMetadata = json.dumps(ast.literal_eval(str(notificationMetadataDict)), indent=2)
    print(f"----- NotificationMetadata = {notificationMetadata}")

    print('Starting step function ...')

    response = stepFnClient.start_execution(
        stateMachineArn=STATE_MACHINE_ARN,
        name=EXECUTION_NAME,
        input=notificationMetadata
    )

    print(f"Execution arn of the Step Function : {response.get('executionArn')}")
    return



요약하자면 - Fast Snapshot Restore 기능의 이점을 누리는 동시에 실제로 필요한 서비스에 대한 지출을 줄일 수 있는 접근 방식을 제시하려고 노력했습니다.

좋은 웹페이지 즐겨찾기