🎰

【Terraform】ECSスロットリング検知とSlackへの自動通知(AWS CloudWatchとChatbotの活用)〜実装〜

2024/04/16に公開

はじめに

こちらの記事はいくつかのシリーズ編です。

https://zenn.dev/take_tech/articles/04707c6594e3fb

今回は実際のコーディングについてお見せできる範囲で記載していこうと思います!
よろしくお願いいたします!

関連するアーキテクチャ

追加したコード

cloudwatch_alarm.tf

resource "aws_cloudwatch_metric_alarm" "ecs_throttling_alarm" {
  alarm_name          = "ecs-throttling-alarm-staging"  
  comparison_operator = "GreaterThanThreshold"  
  evaluation_periods  = "3"                                         
  metric_name         = "ServiceThrottledEvents"
  namespace           = "AWS/ECS"
  period              = "60"
  statistic           = "Sum"
  threshold           = "0"
  alarm_description   = "ECSスロットリング発生時のアラーム"
  actions_enabled     = true
  alarm_actions       = [aws_sns_topic.ecs_throttling_notifications.arn]
  dimensions = {
    ClusterName = "your-cluster-name"
    ServiceName = "your-service-name"
  }
}

各パラメータの用途を簡潔に解説

alarm_name = "ecs-throttling-alarm-staging"
  • (必須)アラーム名のこと
    • どのようなアラームなのかチームに分かりやすい命名を意識する
comparison_operator = "GreaterThanThreshold"
  • (必須)比較演算子のこと
    • GreaterThanThreshold(閾値を超えた)場合、指定したメトリクスが設定された閾値を超えたときにアラームが発動する
evaluation_periods  = "1"
  • (必須)指定された閾値に対してデータを比較する期間の数を定義(ある条件がどれだけ続いたらアラームを鳴らすかを決めるためのもの)
  • 例えば、以下の条件を満たすとアラームが鳴る
    • metric_name が "ServiceThrottledEvents"
    • namespace が "AWS/ECS"
    • period が 60秒(1分)
      • evaluation_periods が 3 と設定されている場合、CPU使用率が閾値を超えた状態が3分間継続している場合にのみアラームが発生する
metric_name = "ServiceThrottledEvents"
  • (以降はすべて任意)アラームに関連付けられるメトリクス名
    • 特定のAWSリソースやサービスから収集したデータポイントを識別する
namespace = "AWS/ECS"
  • アラームに関連付けられるメトリクスの名前空間
    • メトリクスを分類するため
period = "60"
  • 指定された統計が適用される秒数で、有効な値は10、30、60の倍数
    • メトリクスの時間間隔で評価
statistic = "Sum"
  • アラームの関連メトリクスに適用する統計
  • SampleCount、Average、Sum、Minimum、Maximumが使える
    • メトリクスの分析に用いられる
threshold = "0"
  • 閾値(しきいち)のこと
    • アラームが発生する条件を数値で設定するためのパラメータのこと
  • 閾値を超えたらアラートが出る
    • 「0」の場合、スロットリングが1回でも発生した瞬間にアラームが発動するようになる
alarm_description = "ECSスロットリング発生時のアラーム"
  • アラームの説明
actions_enabled = true
alarm_actions = [aws_sns_topic.ecs_throttling_notifications.arn]

- アラームの状態を変更する際に自動でアクションを実行するかどうかを示すもの(アラームが鳴ったときに、特別な行動を取るかどうかを決めるスイッチのようなもの)

  • この設定が「true」(オン)になっていると、アラームが条件を満たしたとき(例えば、ある数値が設定した閾値を超えたとき)に、設定されたアクション(行動)を自動で実行する
  • 例):閾値を超えたら、
    • Slackにアラームを飛ばす
    • Auto Scaleを発動する
  • actions_enabledのデフォルトはtrue
    • falseにするとアラーム条件が満たされても何も起こらない
dimensions = {
    ClusterName = "your-cluster-name"
    ServiceName = "your-service-name"
}
  • アラームの関連付けられたメトリックに関連する特定のリソースを特定するために使用される
  • こちらから特定のクラスターやサービスに対して、メトリクスを監視することが可能

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_metric_alarm#example-usage

sns_topic.tf

resource "aws_sns_topic" "ecs_throttling_notifications" {
  name = "ecs-throttling-notifications-staging"
}

resource "aws_sns_topic_subscription" "slack_notification" {
  topic_arn = aws_sns_topic.ecs_throttling_notifications.arn
  protocol  = "https"
  endpoint  = "https://hooks.slack.com/services/encrypted-url" # SlackのWebhook URL
}

各パラメータの用途を簡潔に解説

name = "ecs-throttling-notifications-staging"

  • トピックの名前を指定

トピックとは

Amazon SNS トピックは、通信チャネルとして機能する論理アクセスポイントです。トピックでは、複数のエンドポイント ( AWS Lambda、Amazon SQS、HTTP/S、E メールアドレスなど) をグループ化できます。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic#name

resource "aws_sns_topic_subscription" "slack_notification"
  • 作成したSNSトピックの役割を記載
topic_arn = aws_sns_topic.ecs_throttling_notifications.arn
  • SNSトピックのARN(AWSリソースを一意に識別するための名前)を指定
    • AWS界のIPアドレスのようなものと解釈(違ったらすみません)
  • 先にTerraformコードで定義した aws_sns_topic リソースのARNを参照しています」という意味
    • つまり、Terraformが自動的に作成したSNSトピックのARNを取得している
protocol  = "https"
  • 通知を送信するプロトコルを指定
endpoint  = "https://hooks.slack.com/services/encrypted-url" # SlackのWebhook URL
  • 通知の送信先エンドポイントを指定(この場合、SlackのWebhook URLを設定)

sns_topic.tfをまとめると

まずaws_sns_topicリソースを使ってecs-throttling-notifications-stagingという名前のSNSトピック(スロットリングの情報を伝えるための場所)を作成

次に、aws_sns_topic_subscriptionリソースを使って、そのトピックに対してサブスクリプション(情報の状態:プロトコル、エンドポイント、AWS界のIPアドレス)を追加

このサブスクリプションは、SlackのWebhook URLにHTTPSプロトコルでメッセージを送るように設定

ここでの topic_arn = aws_sns_topic.ecs_throttling_notifications.arn は、先に作成したトピックのARNを指している。これによりSlackのエンドポイントに正しくメッセージがルーティングされる

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/sns_topic_subscription

chatbot_slack_config.tf

resource "awscc_chatbot_slack_channel_configuration" "ecs_throttling_alert_config" {
  configuration_name = "ecs-throttling-alert-config"
  iam_role_arn       = awscc_iam_role.ecs_throttling_alert_role.arn
  slack_channel_id   = "************"
  slack_workspace_id = "************"
}

resource "awscc_iam_role" "ecs_throttling_alert_role" {
  role_name = "ECS-Throttling-Alert-Role"
  assume_role_policy_document = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "chatbot.amazonaws.com"
        }
      },
    ]
  })
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/CloudWatchFullAccess",
    "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
  ]

各パラメータの用途を簡潔に解説

resource "awscc_chatbot_slack_channel_configuration" "ecs_throttling_alert_config" {
  • AWS ChatbotのSlackチャネル設定を行う新しいリソースを作成
configuration_name = "ecs-throttling-alert-config"
  • Chatbot名を一意に設定
iam_role_arn       = awscc_iam_role.ecs_throttling_alert_role.arn
  • Chatbotが使用するIAMロールのAmazon Resource Name(ARN)を指定
  • ChatbotにAWSリソースの操作を行うための権限を付与
slack_channel_id   = "************"
slack_workspace_id = "************"
}
  • Chatbotがメッセージを送信するSlackのワークスペースとチャンネルを指定

https://slack.com/intl/ja-jp/help/articles/221769328-Slack-URL-または-ID-を確認する#01H8J8QHHEXMJYV14HVZDRR337


resource "awscc_iam_role" "ecs_throttling_alert_role" {
role_name = "ECS-Throttling-Alert-Role"
  • IAMロールの名前を設定
    • AWS内でロールを一意に識別するため
assume_role_policy_document = jsonencode({
  • 特定のAWSサービス(この場合はchatbot.amazonaws.com)がこのロールを引き受ける(Assume Roleする)ことを許可
    • これにより、AWS ChatbotがこのIAMロールを使用してSlackに通知を送ることが可能になる
    Version = "2012-10-17"
    Statement = [
      {
        # 他のAWSサービスがこのロールを引き受けるために必要なアクション
        Action = "sts:AssumeRole"
        # このアクションを許可すること
        Effect = "Allow"
        # AWS Chatbotサービスがこのロールを引き受けることを許可
        Principal = {
          Service = "chatbot.amazonaws.com"
        }
      },
    ]
  })
  # ロールに特定のアクセス権が付与
  # FullAccessは権限が広範なため、限定的な権限に後ほど変える予定
  managed_policy_arns = [
    "arn:aws:iam::aws:policy/CloudWatchFullAccess",
    "arn:aws:iam::aws:policy/AmazonSNSFullAccess"
  ]
}

https://registry.terraform.io/providers/hashicorp/awscc/latest/docs/resources/chatbot_slack_channel_configuration

まとめ

この記事では、問題発見から要件定義までの工程を詳細に解説し、実際のAWSの設定を通じてその適用例を示しました。特にAWS CloudWatchとSNSを使用したスロットリングの監視と通知の自動化に焦点を当て、Terraformを使用してこれらのサービスを設定する具体的な手順を紹介しました。このシリーズは、問題発見から解決までの一連の「リアル」をお届けすることを目指しています

続く

次回の記事では、主にコードの修正と今回設定したアラームと通知システムの動作検証に焦点を当てます。また、アラームの感度調整や、より高度なメトリック分析に基づくアラーム戦略の展開についても掘り下げていく予定です。よろしくお願いいたします!

今回もご購読くださりありがとうございました!

追記

実装の続きをリリースしました!特にセキュリティは知らないと損なので、ぜひご一読ください!

https://zenn.dev/take_tech/articles/04707c6594e3fb

https://zenn.dev/take_tech/articles/ac0704b50684da

https://zenn.dev/take_tech/articles/4f728035d166b1

Discussion