EC2やRDS、ELBの停止忘れ、削除し忘れを防ぐ!LambdaScheduleイベント #reinvent

AmazonLambda

コンニチハ。千葉です。

突然ですが、開発環境などで使っているEC2やRDS、ELBを停止し忘れた、消し忘れた!という経験をお持ちの方へ。

私、よくパソコン抱っこしながら寝落ちするのですが、ELBを作成しっぱなし、課金発生してた!ということがあります。

無駄にお金を払わないように、インスタンス停止や不要なリソースの削除はコマメに行いたいところです。

そんな中、新しくLambdaScheduleイベントがリリースされました。これは使うしかない!ということで、リソースの状況を教えてくれるツールを作ってみました。

構成

money-info-0

Lambdaで1日1回スケジュールをトリガーに発火させます。 そこで、EC2、RDS、ELBの起動状況を取得、SNS経由からメールで通知してくれます。

リソースが起動している場合は、こんな感じでメールがきます。逆にリソースが起動していない時は、メールは来ません!

money-info-13

作ってみた

SNSの作成

まず、メール送信するためにSNSトピックを作成します。

SNSの画面から、[Topics] > [Create new topic]を選択します。

money-info-1

[Topic name]と[Display name]を入力します。

money-info-2

リソース状況の通知先のメールアドレスを設定します。先ほど作成した、トピックにチェックを入れ、[Actions] > [Subscribe to topic]を選択します。

money-info-3

[Email]を選択し、通知先のメールアドレスを入力します。

money-info-4

先ほど入力したメール宛に、購読するかの確認メールが来ます。[Confirm subscription]をクリックして購読登録します。

money-info-12

SNS側でメールアドレスが購読状態になっているかを確認します。トピック一覧より、対象トピックのARNをクリックします。 また、ARNは後で使うのでメモっておきます。

money-info-5

[Subscription ID]が[arn:aws:sns:〜]、[Endpoint]に登録したメールアドレスが表示されているかを確認します。

これで、SNSの作成は完了です。

money-info-6

Lambdaファンクションの作成

今回は、Pythonでコードを記述します。 それではLambdaファンクションを作成していきます。

[Create a Lambda function]をクリックし、Lambdaファンクションを作成していきます。

money-info-14

[Skip]をクリックします。

money-info-8

[Name]、[Description]を入力し、[Python]を選択します。

money-info-15

[Lambda function code]には、下記のコードを入力します。

[TOPIC_ARN]には、先ほど作成したSNSトピックのARN(先ほどメモしたもの)を入力します。

import boto3

TOPIC_ARN = 'arn:aws:sns:ap-northeast-1:XXXX:XXXX'

def lambda_handler(event, context):
    try:
        # Check for EC2
        ec2 = boto3.client('ec2')
        ec2_resp = ec2.describe_instances(Filters=[{'Name':'instance-state-name','Values':['running']}] )

        ec2_count = len(ec2_resp['Reservations'])

        if not ec2_count == 0:
            send_message.append("[EC2 is running!!]")
            for i in range(0, ec2_count):
                send_message.append(ec2_resp['Reservations'][i]['Instances'][0]['Tags'][0]['Value'])
            send_message.append("")

        # Check for ELB

        elb = boto3.client('elb')
        elb_resp = elb.describe_load_balancers()

        elb_count = len(elb_resp['LoadBalancerDescriptions'])

        if not elb_count == 0:
            send_message.append("[ELB is running!!]")
            for i in range(0, elb_count):
                send_message.append(elb_resp['LoadBalancerDescriptions'][i]['LoadBalancerName'])
            send_message.append("")

        # Check for RDS

        rds = boto3.client('rds')
        rds_resp = rds.describe_db_instances()

        rds_count = len(rds_resp['DBInstances'])

        if not rds_count == 0:
            send_message.append("[RDS is running!!]")
            for i in range(0, rds_count):
                send_message.append(rds_resp['DBInstances'][i]['DBInstanceIdentifier'])
            send_message.append("")

        # Send mail

        send_subject = "[AWS]Money Save"
        send_message = ["Please check resources...\n"]

        for i in send_message:
            print(i)

        sns = boto3.client('sns')

        sns_resp = sns.publish(
            TopicArn = TOPIC_ARN,
            Message = "\n".join(send_message),
            Subject = send_subject
        )
        return 0
    except Exception as e:
        print(e)
        print('Error getting object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e

[Lambda function handler and role] > [Role]にて、今回用のRoleを作成します。

[Basic execution role]を選択します。

money-info-9

ロールの作成画面が表示されます。(chromeではポップアップの許可が必要だったため、適宜許可します)

[IAM ロール]は[新しいIAMロールの作成]を選択、[ロール名]を入力します。

[編集] > [OK]をクリックします。

money-info-10

ポリシードキュメントには、以下を入力します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeInstances",
                "rds:DescribeDBInstances",
                "elasticloadbalancing:DescribeLoadBalancers",
                "sns:Publish",
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        }
    ]
}

[Advanced settings]で、Lambda実行時間のタイムアウトを[30秒]にします。

[Next]をクリックします。

money-info-11

設定内容を確認し、[Create function]をクリックします。

money-info-16

テスト実行してみます。[Save and test]をクリックします。

money-info-17

Lambdaファンクションが実行されます。下にスクロールし、実行結果を確認し[succeeded]となっていることを確認します。

money-info-18

ここで、

  • EC2インスタンスが"起動"している
  • ELBが"存在"している
  • RDSインスタンスが"存在"している

場合、登録したメールアドレスにメールが来ます。

money-info-13

あとは、1日1回スケジュール実行するようにトリガーの設定をして終わりです。

[Event sources]タブを選択し、[Add event source]をクリックします。

money-info-19

[Ebvent source type]で[Scheduled Event]を選択。[Schedule expression]で[rate(1 day)]を選択します。

[Submit]をクリックして設定完了です。

money-info-20

あとは、リソースが起動している場合は日時でメールが来ます。

さいごに

Lambdaスケジュール、とっても便利です。スナップショット等、cron専用に立てていたサーバの代替としても利用できそうです。