LoginSignup
7
10

More than 5 years have passed since last update.

AWSで起動しているインスタンスをPythonでチェックしてSlackに投稿する

Last updated at Posted at 2019-01-03

Pythonのお勉強とEC2インスタンス停止忘れ防止のため、起動しているEC2インスタンスをチェックしてSlackに投稿するようにしたメモ。

参考リンク

以下の先人の記事を参考に作成。

動作イメージ

image.png

Slackの準備

Webhook URLの取得

以下を参考にWebhook URLを取得する。

AWS CLI

Pythonの前にAWS CLIで起動しているインスタンスを確認してみる。

AWS CLIをセットアップする。

pip3 install awscli
aws configure

インスタンスを確認する。

コマンド
aws ec2 describe-instances --filters "Name=instance-state-name,Values=running"

Python + AWS Lambda

AWS Lambda上のPythonからSlackに投稿する。

IAM Roleの作成

IAMコンソールでRoleを作成し、AWSLambdaBasicExecutionRoleAmazonEC2ReadOnlyAccessのポリシーをアタッチする。

image.png

作成したRoleのARNを確認しておく。

コード作成

作成するファイルは以下の3つ。→GitHub

.
├── lambda.json
├── lambda_function.py
└── requirements.txt

lambda.jsonはlambda-uploderが使用するJSON形式のLambda関数の定義ファイル。先ほど作成したRoleのARN、Slack Webhook URL、Slackチャンネル名を指定する。lambda-uploaderの使い方と、jsonの書き方は以下を参照。

lambda.json
{
  "name": "aws_instance_checker",
  "description": "My AWS instance checker.",
  "region": "ap-northeast-1",
  "runtime": "python3.7",
  "handler": "lambda_function.lambda_handler",
  "role": "arn:aws:iam::hogehoge",
  "timeout": 300,
  "memory": 128,
  "variables":
    {
      "SLACK_WEBHOOK_URL": "https://hooks.slack.com/services/hogehoge",
      "SLACK_CHANNEL": "#hogehoge"
    }
}

lambda_function.pyが関数本体。以下を参考に作成。

lambda_function.py
import datetime
import os
import json

import boto3
import pytz
import requests

SLACK_WEBHOOK_URL = os.environ['SLACK_WEBHOOK_URL']
SLACK_CHANNEL = os.environ['SLACK_CHANNEL']


def get_instances():
    """boto3を使って全てのリージョンで起動しているEC2インスタンスを取得する

    :return: instances
    """

    # 全リージョンを取得
    client = boto3.client('ec2')
    regions = client.describe_regions()['Regions']

    instances = []

    # 各リージョン毎に繰り返し
    for region in regions:
        client = boto3.client('ec2', region_name=region['RegionName'])

        response = client.describe_instances(
            Filters=[
                {
                    'Name': 'instance-state-name',
                    'Values': [
                        'running',
                    ]
                },
            ]
        )

        reservations = response['Reservations']

        if not reservations:
            continue

        for reservation in reservations:
            instance = dict()
            instance['id'] = reservation['Instances'][0]['InstanceId']
            tags = reservation['Instances'][0]['Tags']
            instance['name'] = 'null'
            for tag in tags:
                if tag['Key'] == 'Name':
                    instance['name'] = tag['Value']
            instance['type'] = reservation['Instances'][0]['InstanceType']
            instance['region'] = region['RegionName']
            instances.append(instance)

    return instances


def build_message(instances):
    """SlackにPOSTするメッセージボディを作成する

    :param instances:
    :return: message
    """

    if not instances:
        return None

    now = datetime.datetime.now(pytz.timezone('Asia/Tokyo'))

    text = '{}現在稼働しているEC2インスタンス一覧'.format(now.strftime('%Y年%m月%d日%H時%M分'))
    atachement_text = ''
    for instance in instances:
        atachement_text += 'name: {}, type: {}, id: {}, region: {}\n'.format(
            instance['name'], instance['type'], instance['id'], instance['region'])

    atachements = {'text': atachement_text, 'color': 'warning'}

    message = {
        'text': text,
        'channel': SLACK_CHANNEL,
        'attachments': [atachements],
    }
    return message


def post_message(message):
    """SlackにPOSTする

    :param message:
    :return:
    """

    response = requests.post(SLACK_WEBHOOK_URL, data=json.dumps(message))
    response.raise_for_status()


def lambda_handler(event, context):

    instances = get_instances()

    message = build_message(instances)

    if message:
        post_message(message)

requirements.txtは使用するモジュールの定義。

requirements.txt
boto3
pytz
requests

アップロード

lambda-uploaderをインストールする。

pip3 install lambda-uploader 

アップロードする。

$ lambda-uploader
λ Building Package
λ Uploading Package
λ Fin
$

スケジュール実行

lambda-uploaderによってLambda関数が作成されるので、LambdaコンソールからトリガーとしてCloudWatch Eventsを追加する。

image.png

スケジュールを設定する。確認のためとりあえずcron(* * * * ? *)(毎分実行)を設定する。

image.png

Slackに投稿されることを確認する。

image.png

上手く投稿できなかったら、CloudWatch Logsでログを確認する。上手く投稿が確認できたら、CloudWatch Eventsでスケジュールをcron(0 * * * ? *)(毎時)に変更する。

image.png

7
10
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
7
10