10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

EC2インスタンスの状態変化をLambda(boto3)とSNSで自動通知する

Last updated at Posted at 2018-12-20

はじめに

皆さま初めましてjimbot3です。botと入っておりますがchatbotではなくboto3のほうです。

Qiitaを読む習慣を持っている皆さまであれば、1度は"サーバレス"という単語を聞いたことがあると思います。
ざっくり言うと「サーバを持たずコードを実行する仕組み」のこと。
今回以下の理由でAWSのサーバレスアーキテクチャ"Lambda"とLambdaのトリガ用に"CloudWatch"を使ってサーバレスを体験してみました。

  • これから徐々に、もしくは急激にサーバレスは流行るだろうと考えている(jimbot3リサーチ社調べ)
  • 自分のコーディングスキルを向上させたい
  • 「この前サーバレスやってみたんだけど~」とか言ってみたい
  • 研修でLambdaを使う課題が出されたから、と言う最たる理由があったりなかったり

つくってみたLambdaとその解説

1. EC2インスタンスの起動・停止をLambda経由でSNS(E-mail)通知するLambda

実行する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'
    )
  1. mystatusに取得したいEC2インスタンスのStatusを格納
  1. 停止(==stop)状態であればstopメッセージ/起動(==start)状態であればstartメッセージのメール送付
↑のLambdaをトリガーさせるCloudWatchの中身

※Lambda画面からCloudWatch Eventsの設定もできますが今回はCloudWatch画面での設定
clwa.PNG

取得したいEC2のインスタンスIDを指定し、起動もしくは停止したのをトリガーにLambdaを実行

届いたメールはこんな感じ
gmail1.PNG

つまりLambdaとCloudWatchを使うことで以下のような通知が行える

  1. EC2のステータス変更をきっかけにCloudWatchがLambdaを実行
  2. LambdaでEC2の状態を拾いメール

2. 24hのEC2インスタンスの起動・停止の集計をSNS(E-mail)通知するLambda

実行する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. 先ほどの1. で作った起動停止Lambdaの過去24時間(1日)のログを"client.filter_log_events"でフィルターし拾う。
  2. そのログをtempファイルとしてに1行ずつフォーマットしながら格納。
  3. 格納が終わったファイルを開き、そのtempファイルの中身をメッセージとしてメールの送付。ログが無い場合は起動/停止が無かった旨のメールを送付。
↑のLambdaをトリガーさせるCloudWatchの設定
clwa22.PNG

Lambdaをcronでスケジュール実行。(0 8 * * ? *)だと日次で日本時間の17:00に実行されます。

届いたメールはこんな感じ
mail2.PNG

つまりLambdaとCloudWatchを使うことで以下のような通知が行える

  1. 日次で日本時間の17:00にCloudWatchがLambdaを実行
  2. Lambdaで過去24hのEC2インスタンスの起動停止履歴を拾いメール

感想

  • 取り敢えず1回手を動かすとサーバレスの仕組みは"何となく"理解できる。
  • 1回触ってみると「次はこれを作ってみよう」と思えるので、成長のサイクルが生まれるサービスだと思う。
    (例えばEC2やVPCを1回作っても、もう1回作ってみようとは私は思えなかった。)
  • LambdaはAWSのサービスであるが必要なのはプログラミングスキルで、AWSコンソールのボタンポチポチスキルではない。
10
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?