Compute OptimizerのレコメンデーションをEventBridge Scheduler+Lambdaで定期通知してみた
こんにちは、ゲームソリューショングループのsoraです。
今回は、Compute OptimizerのレコメンデーションをEventBridge Scheduler+Lambdaで定期通知してみたことについて書いていきます。
構成
EventBridge Schedulerで指定した間隔でLambdaを呼び出して、Compute Optimizerのレコメンデーションを取得する構成です。
取得した後は、SNS経由でSlack通知するようにします。
取得する情報について、EC2で過剰なプロビジョニングとなっているサーバに関してのサマリーを取得します。
AWSマネジメントコンソールで表示されているようなサーバごとの推奨事項を通知しようと思ったのですが、単純に取得できずに処理が複雑化しそうだったため、サマリーとしています。
サーバごとの推奨事項を取得するには、CSVエクスポートを絡めればおそらく可能だと思います。
Terraformでの作成
Terraformを使って作成します。
Compute Optimizerのチェック結果はバージニア北部から取得する必要があります。
terraform { #AWSプロバイダーのバージョン指定 required_providers { aws = { source = "hashicorp/aws" version = "~> 4.51.0" } } } #AWSプロバイダーの定義 provider aws { # Compute Optimizerのチェック結果はバージニア北部から取得する必要がある region = "us-east-1" } #AWSアカウントIDの取得 data aws_caller_identity current {} #============ IAMロール作成 start ============ ##EventBridge Sheduler data aws_iam_policy_document events_assume_role { statement { effect = "Allow" principals { type = "Service" identifiers = ["scheduler.amazonaws.com"] } actions = ["sts:AssumeRole"] } } resource aws_iam_role iam_for_events { name = "EventBridge_ComputeOptimizer_Notification_Role" assume_role_policy = data.aws_iam_policy_document.events_assume_role.json managed_policy_arns = ["arn:aws:iam::aws:policy/service-role/AWSLambdaRole"] } ##Lambda(Compute Optimizerからの情報取得用) data aws_iam_policy_document lambda_assume_role { statement { effect = "Allow" principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } actions = ["sts:AssumeRole"] } } resource aws_iam_role iam_for_lambda { name = "Lambda_ComputeOptimizer_Notification_Role" assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json inline_policy { name = "my_inline_policy" policy = jsonencode({ Version = "2012-10-17" Statement = [ { Action = ["sns:Publish"] Effect = "Allow" Resource = "*" }, ] }) } managed_policy_arns = [ "arn:aws:iam::aws:policy/ComputeOptimizerReadOnlyAccess" ] } #============ IAMロール作成 end ============ #============ リソース作成 start ============ ##SNS(トピック) ###トピックの作成 resource aws_sns_topic compute_optimizer_topic { name = "ComputeOptimizer-notification-topic" } data aws_iam_policy_document sns_assume_role { statement { effect = "Allow" principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } actions = ["sns:Publish"] resources = [aws_sns_topic.compute_optimizer_topic.arn] } } resource aws_sns_topic_policy sns_topic_policy { arn = aws_sns_topic.compute_optimizer_topic.arn policy = data.aws_iam_policy_document.sns_assume_role.json } ##Lambda(Compute Optimizerからの情報取得用) data archive_file lambda_computeoptimizer { type = "zip" source_file = "lambda/lambda_computeoptimizer.py" output_path = "lambda_computeoptimizer.zip" } resource aws_lambda_function lambda_computeoptimizer { filename = "lambda_computeoptimizer.zip" function_name = "compute-optimizer-notification" role = aws_iam_role.iam_for_lambda.arn handler = "lambda_computeoptimizer.lambda_handler" source_code_hash = data.archive_file.lambda_computeoptimizer.output_base64sha256 runtime = "python3.9" environment { variables = { SNSTopicArn = aws_sns_topic.compute_optimizer_topic.arn, AccountId = data.aws_caller_identity.current.account_id } } } ##Lambda(Slack通知用) data archive_file lambda_slack { type = "zip" source_file = "lambda/lambda_slack.py" output_path = "lambda_slack.zip" } resource aws_lambda_function lambda_slack { filename = "lambda_slack.zip" function_name = "compute-optimizer-to-slack" role = aws_iam_role.iam_for_lambda.arn handler = "lambda_slack.lambda_handler" source_code_hash = data.archive_file.lambda_slack.output_base64sha256 runtime = "python3.9" #slack通知先 environment { variables = { HookURL = "[SlackのWebHookURL]" ChannelName = "[チャンネル名]" } } } resource aws_lambda_permission lambda_slack_permission { action = "lambda:InvokeFunction" function_name = aws_lambda_function.lambda_slack.function_name principal = "sns.amazonaws.com" source_arn = aws_sns_topic.compute_optimizer_topic.arn } ##EventBridge Sheduler resource aws_scheduler_schedule eventbridge { name = "compute-optimizer-notification-schedule" description = "Compute Optimizer Notification" flexible_time_window { mode = "OFF" } schedule_expression = "cron(0 0 1 * ? *)" schedule_expression_timezone = "Asia/Tokyo" target { arn = aws_lambda_function.lambda_computeoptimizer.arn role_arn = aws_iam_role.iam_for_events.arn } } ##SNS(サブスクリプション) resource aws_sns_topic_subscription slack_subscription { topic_arn = aws_sns_topic.compute_optimizer_topic.arn protocol = "lambda" endpoint = aws_lambda_function.lambda_slack.arn }
Lambdaコード
今回の構成では、Compute Optimizerから情報取得する用とSlack通知用の2つがあります。
Compute Optimizerから取得する用のLambda(Python)で使っているSDKについては、以下をご参照ください。
ComputeOptimizer — Boto3 Docs 1.26.87 documentation
import boto3 import json import os AccountID = os.environ['AccountId'] SNSTopicArn = os.environ['SNSTopicArn'] def lambda_handler(event, context): # Compute Optimizerから推奨事項を取得 # クライアント作成 client = boto3.client('compute-optimizer') # リクエスト発信 response = client.get_recommendation_summaries( accountIds=[AccountID], nextToken="", maxResults=10 ) # メッセージ生成に必要な情報の抽出 message = [] message.append("Compute OptimizerのEC2に関するコスト最適化の推奨事項を通知") # メッセージ作成 for flag in response['recommendationSummaries']: if flag['recommendationResourceType'] == "Ec2Instance": for flag_summary in flag['summaries']: if flag_summary['name'] == "OVER_PROVISIONED": message.append("EC2インスタンス") message.append(f"ステータス: {flag_summary['name']} ,アカウントID: {flag['accountId']} 推定削減額: {flag_summary['value']}") # メッセージをSNSに送信 # 通知を送信するSNSトピックのARNを指定 sns_client = boto3.client('sns') sns_topic_arn = SNSTopicArn sns_client.publish( TopicArn=sns_topic_arn, Message=json.dumps(message, indent=3, ensure_ascii=False) )
Slack通知用のLambdaは割愛します。
実行結果
EventBridge Schedulerで指定したタイミングで通知がきました。
推定削減額は0ですが、正常に動作して通知できています。
最後に
今回は、Compute OptimizerのレコメンデーションをEventBridge Scheduler+Lambdaで定期通知してみたことを記事にしました。
どなたかの参考になると幸いです。