LoginSignup
1
0

More than 3 years have passed since last update.

SlackチャンネルにEC2インスタンスが落ちたことを通知してくれるようにしてみた

Last updated at Posted at 2020-07-20

背景

時折、開発環境のEC2インスタンスが勝手に落ちていることがあり、気が付いた人からの問い合わせでその都度手動でEC2インスタンスを再起動していました。
開発者達が開発に集中できるようにするために自動で通知してくれるような仕組みを構築しました。

実装一覧

  • SlackチャンネルにEC2インスタンスがstoppedになったことを通知できるようにする
  • stoppedになったら、自動で再起動できるようにする
  • 上記の機能を9:00~21:00の間に限定できるようにする

9:00~21:00の間に制限を設けている理由ですが、開発環境ではコスト改善のために21時になったら、自動で開発環境の全てのEC2インスタンスがshutdownされ、翌朝9時になったら自動で起動できるようにしてあります。
なので、仮に上記の機能が21時以降も有効になってしまうと、幾つものEC2インスタンスのステータス通知がSlackチャンネルを埋めるだけでなく、深夜早朝帯も開発環境が起動され続けるという恐れがあります。

使用ツール

  • CloudWatch Event
  • Lambda
  • Incoming Webhook

手順

①SlackからIncoming Webhookアプリをインストールする
何かしらのサービス情報をSlackのチャンネルに通知するためにはIncoming WebhookというSlackアプリを活用することで実現可能となります。公式サイト
インストール後、サービス情報を共有したいSlackチャンネルを選択し、WebhookURLを控えておきます。
vGx3klsIw5EqkjY1591324726_1591325055.png
②Lambda関数を作成する
新規でLambda関数を作成し、以下の関数を書きます。
image.png

lambda_function.py
from __future__ import print_function
from time import strptime, strftime

import os, json, boto3, urllib.request

#GMT表記
before = strptime('00:00:00', '%H:%M:%S')
after = strptime('11:59:00', '%H:%M:%S')
now = strptime(strftime('%H:%M:%S'), '%H:%M:%S')

print(now)

#自動起動/シャットダウンバッチに引っかからないようにJST9:00-JST21:00の間で処理を動かすようにしている
if (now >= before and now <= after):

   #変数eventの中身がCloudWatch Eventから受け取ったEC2インスタンスのstop
   def lambda_handler(event,context):

      instances = [ event ]
      region = 'ap-northeast-1'
      ec2 = boto3.client('ec2', region_name=region)

      #色付きメッセージ発行
      attachments = {
        'attachments': [{
          # titleのリンクをクリックするとtitle_linkで設定したページへ飛びます。
          'title': 'EC2が停止しました。',
          'title_link': 'https://api.slack.com/docs/message-attachments',
          'color': "warning",
        }]
      }

      req = json.dumps(attachments).encode('ascii')

      message_color = urllib.request.Request(os.environ['slackUrl'], req )

      try:
         response = urllib.request.urlopen(message_color)
         response.read()

      except Exception as e:
         print(e)

      #インスタンスの起動停止メッセージ
      message_stop = {
         'text': "<!here> EC2 Instance " + (event) + " stopped"
      }

      data = json.dumps(message_stop).encode('ascii')

      req = urllib.request.Request(os.environ['slackUrl'], data )
      try:
          response = urllib.request.urlopen(req)
          response.read()

          print("Message posted: %s" % message_stop )
      except Exception as e:
          print(e)

      #停止したインスタンスの再起動
      ec2.start_instances(InstanceIds=instances)
      message_restart = {
         'text': "started your instances: " + str(instances)
      }

      data2 = json.dumps(message_restart).encode('ascii')

      req = urllib.request.Request(os.environ['slackUrl'], data2 )
      try:
          response = urllib.request.urlopen(req)
          response.read()

          print("Message posted: %s" % message_restart )
      except Exception as e:
          print(e)

   #自動起動/シャットダウンが走る9時前、21時以降は処理をさせない
else:
   print("out time of function")

関数内で未定義の変数slackUrlはLambda側から取得したWebhookURLをセットしました。
image.png
③CloudWatch EventでLambda関数が発動するルールを作成する
EC2インスタンスがstoppedになったら先ほど作成したLambda関数を起動できるようにルールを作成します。
image.png
この時、Lambda関数へ渡す入力内容を絞ることでSlackチャンネルに表示される内容を見やすいものに加工することができます。
※全表示の場合(一部モザイク処理)
ec2.png
以上で、Slackチャンネルへ通知する手順は完了しました。最後にEC2インスタンスを停止させて、Slackチャンネルへ通知が届き、再起動ができるか確認します。
ec3.png
ちゃんと実装したかったことができるようになりました。

所感

AWSとSlackの連携方法として、CloudWatch AlarmからLambdaを飛ばしてSlackチャンネルへアラーム内容を連携する方法が一般的で、検索すると多くの記事が出てきてLambda関数にもそれ用のテンプレートがあります。
また、最近AWSとSlackが、提携を発表しそれぞれのサービスの結びつきが今後ますます強くなっていくと思われます。参考リンク
最近ですと、AWS Chatbotで簡単にAWSサービスの内容をSlackへ連携しやすくなりましたが、まだ提供できるサービスが少ないためCloudWatch Eventでも対応できるようになりましたら検証してみたいと思います。

1
0
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
1
0