EC2 인스턴스의 상태 변화를 Lambda(boto3)와 SNS로 자동 통지

소개



여러분 처음 뵙겠습니다 jimbot3입니다. bot이라고 들어 있습니다만 chatbot이 아니라 boto3쪽입니다.

Qiita를 읽는 습관을 가지고 있는 여러분까지 있으면, 한번은 "서버리스"라는 단어를 들은 적이 있다고 생각합니다.
어쨌든 말하면 「서버를 가지지 않고 코드를 실행하는 구조」의 일.
이번에는 다음과 같은 이유로 AWS의 서버리스 아키텍처 "Lambda"와 Lambda를 트리거하기 위해 "CloudWatch"를 사용하여 서버리스를 경험해 보았습니다.
  • 앞으로 서서히 또는 급격하게 서버리스는 유행 할 것이라고 생각하고있다 (jimbot3 리서치 사 조사)
  • 자신의 코딩 스킬을 향상시키고 싶다
  • "이전 서버리스 해 보았지만 ~"라고 말하고 싶다
  • 연수에서 Lambda를 사용하는 과제가 나왔기 때문에, 말하는 가장 좋은 이유가 있거나 없거나

  • 만들었던 람다와 그 해설



    1. Lambda를 통해 EC2 인스턴스의 시작 및 중지를 SNS(E-mail) 통지하는 Lambda



    실행할 람다의 내용
    import boto3
    
    def lambda_handler(event, context):
        ec2 = boto3.client('ec2')
        sns = boto3.client('sns')
        mystatus= ec2.describe_instances(
            Filters=[{'Name':'instance-id', 'Values':['i-04XXXXXXXXXXXXXXX']}] # 取得したいEC2のインスタンスIDを入力
        )["Reservations"][0]["Instances"][0]['State']['Name'] 
        if mystatus == 'stopped':
            print ('stop!!')
            topic = 'arn:aws:sns:ap-northeast-1:08XXXXXXXXXX:Myaddress' # 送付したいARNを入力
            subject = 'StatusChangeMail'
            message = 'stop!!'
            region = '{ap-northeast-1}'
            response = sns.publish(
                TopicArn=topic,
                Message=message,
                Subject=subject,
                MessageStructure='raw'
        )
        elif mystatus == 'running': # 後程説明しますが、今回はCloudWatchでrunningとstoppedの値のみ拾う仕様なのでelifでrunningを指定しております
            print ('running!!')
            topic = 'arn:aws:sns:ap-northeast-1:08XXXXXXXXXX:Myaddress' # 送付したいARNを入力
            subject = 'StatusChangeMail'
            message = 'running!!'
            region = '{ap-northeast-1}'
            response = sns.publish(
                TopicArn=topic,
                Message=message,
                Subject=subject,
                MessageStructure='raw'
        )
    
  • mystatus에 취득하고 싶은 EC2 인스턴스의 Status를 포함
  • 정지(==stop) 상태이면 stop 메시지/기동(==start) 상태이면 start 메시지의 메일 보내기


  • ↑의 Lambda를 트리거하는 CloudWatch의 내용

    ※Lambda 화면에서 CloudWatch Events의 설정도 할 수 있습니다만 이번은 CloudWatch 화면에서의 설정


    얻고 싶은 EC2의 인스턴스 ID를 지정하고 시작하거나 중지 한 것을 트리거로 Lambda 실행

    받은 메일은 이런 느낌



    즉, Lambda와 CloudWatch를 사용하여 다음과 같은 알림을 할 수 있습니다.
    1. EC2의 상태 변경을 계기로 CloudWatch가 Lambda를 실행
    2. Lambda에서 EC2 상태를 데리러 메일

    2. 24h의 EC2 인스턴스의 기동·정지의 집계를 SNS(E-mail) 통지하는 Lambda



    실행할 람다의 내용
    import boto3
    import datetime
    import calendar
    
    def lambda_handler(event, context):
        group_name = '/aws/lambda/XXXXXXX' # 先ほどの1.でつくった起動停止Lambdaのロググループを入力
        client = boto3.client('logs')
        timeto = datetime.datetime.now() # print(timeto) → 2018-12-08 10:24:20.499645
        u_to = calendar.timegm(timeto.utctimetuple()) * 1000 # print(u_to) → 1544264660000
        timefrom = timeto - datetime.timedelta(days=1) # print(timefrom) → 2018-12-07 10:24:20.499645
        u_from = calendar.timegm(timefrom.utctimetuple()) * 1000 # print(u_from) → 1544178260000
        #u_toとu_fromを*1000したのは後のfilter_log_eventsの期間指定がミリ秒のため
    
        response = client.filter_log_events(
            logGroupName=group_name,
            startTime = u_from,
            endTime = u_to
        )
        #print(response) → {'events': [], 'searchedLogStreams': [], 'ResponseMetadata': {'RequestId': '6cdXXXXX~
    
        file_name = '/tmp/' + 'temp.log'
        with open(file_name, 'a') as f:
            for stream in response['events']:
                message = '[{}] {}'.format(datetime.datetime.fromtimestamp(int(str(stream['timestamp'])[:10])) 
                + datetime.timedelta(hours=9), stream['message']) #[:10]はミリ秒を秒に直すため14桁のうち左から10桁
                f.write(message)
    
        topic = 'arn:aws:sns:ap-northeast-1:08XXXXXXXXXX:Myaddress' # 送付したいARNを入力
        subject = '過去24時間分 起動停止記録'
        file = open(file_name, 'r')
        message = file.read()
        sns = boto3.client('sns')
        region = '{ap-northeast-1}'
        if message:
            response = sns.publish(
                TopicArn=topic,
                Message=message,
                Subject=subject,
                MessageStructure='raw'
            )
        else:
            response = sns.publish(
                TopicArn=topic,
                Message="直近24時間に起動/停止はございませんでした。",
                Subject=subject,
                MessageStructure='raw'
            )
    
  • 방금 전의 1. 로 만든 기동 정지 Lambda의 지난 24시간(1일)의 로그를 "client.filter_log_events"로 필터 해 줍는다.
  • 그 로그를 temp 파일로서에 1 행씩 포맷하면서 저장.
  • 저장이 끝난 파일을 열어, 그 temp 파일의 내용을 메세지로서 메일의 송신. 로그가 없는 경우는 기동/정지가 없었다고 하는 메일을 송부.


  • ↑의 Lambda를 트리거하는 CloudWatch 설정



    Lambda를 cron으로 스케줄 실행. (0 8 * * ? *)라고 일차로 일본 시간의 17:00에 실행됩니다.

    받은 메일은 이런 느낌



    즉, Lambda와 CloudWatch를 사용하여 다음과 같은 알림을 할 수 있습니다.
    1. 일차로 일본 시간 17:00에 CloudWatch가 Lambda를 실행
    2. Lambda에서 지난 24h의 EC2 인스턴스 시작 중지 내역을 데리러 메일

    감상


  • 굳이 한번 손을 움직이면 서버리스의 구조는 "어쩐지"이해할 수 있다.
  • 1회 만져 보면 「다음은 이것을 만들어 보자」라고 생각되기 때문에, 성장의 사이클이 태어나는 서비스라고 생각한다.
    (예를 들면 EC2나 VPC를 1회 만들어도, 또 1회 만들어 보려고는 나는 생각되지 않았다.)
  • Lambda는 AWS 서비스이지만 필요한 것은 프로그래밍 기술이며 AWS 콘솔의 버튼 포치 포치 기술이 아닙니다.
  • 좋은 웹페이지 즐겨찾기