IaCの恩恵をわかりやすくすぐに受けやすいのは、Cloudwatch Alarmなどの監視項目だと思っています。
特にSQSキューなどは基本的に監視項目が似通っているため、似たようなものを大量に登録、管理する事が多いでしょう。
今回は、よくあるアラートの設定項目をterraformでさっと量産する方法を覚書として記載しておきます。
よくある監視項目
毎回、SQSキューを作った後にとりあえず設定しておきたい監視項目は以下のようなものがあるかと思います。
- デッドレターキューなどにメッセージが入った
- キューされたメッセージがxxx件を超えた
- 未処理のメッセージが放置されたままxxx日が過ぎた
このへんにフォーカスした設定を書いてみます。
terrafromの設定
-
今回、通知に使っている AWS SNS Topic は別途定義されているものとします。
(もちろんEventBridgeなどSNS以外の方法でaction eventを受け取ってもいいでしょう) -
module化を避け、1ファイルで完結させます。
locals {
queues = [
{
queue_name : "sample-A-queue", // SQSキュー名
alert_queue_count = [200], // 何個メッセージがたまったらアラートを出すか
alert_oldest_message_day = [5, 7, 10, 13], // 一番古いメッセージがこの日数を検知したらアラート
},
{
queue_name : "sample-B-queue-dead"
alert_queue_count = [1, 10, 20, 30, 100],
alert_oldest_message_day = [5, 7, 10, 13],
},
{
queue_name : "sample-C-queue.fifo",
alert_queue_count = [200],
alert_oldest_message_day = [5, 7, 10, 13],
},
]
}
// 使いやすいようにデータ変換処理
locals {
queue_count_alert_source = flatten([for q in local.queues : [for c in q.alert_queue_count : {
queue_name = q.queue_name
count = c
}]])
oldest_message_alert_source = flatten([for q in local.queues : [for day in q.alert_oldest_message_day : {
queue_name = q.queue_name
day = day
seconds = day * 24 * 3600
}]])
}
// キュー数監視アラート
resource aws_cloudwatch_metric_alarm queue_count_alarm {
count = length(local.queue_count_alert_source)
alarm_name = "sqs_count_${local.queue_count_alert_source[count.index]["queue_name"]}_over_${local.queue_count_alert_source[count.index]["count"]}"
alarm_description = "message detected: SQS ${local.queue_count_alert_source[count.index]["queue_name"]} > ${local.queue_count_alert_source[count.index]["count"]} "
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
metric_name = "ApproximateNumberOfMessagesVisible"
namespace = "AWS/SQS"
period = 300
statistic = "Minimum"
threshold = local.queue_count_alert_source[count.index]["count"]
alarm_actions = [aws_sns_topic.fatal.arn]
ok_actions = [aws_sns_topic.fatal.arn]
insufficient_data_actions = []
treat_missing_data = "ignore" //欠落データを無視
dimensions = {
QueueName = local.queue_count_alert_source[count.index]["queue_name"]
}
}
// 放置メッセージ監視アラート
resource aws_cloudwatch_metric_alarm oldest_message_days {
count = length(local.oldest_message_alert_source)
alarm_name = "sqs_old_${local.oldest_message_alert_source[count.index]["queue_name"]}_day_${local.oldest_message_alert_source[count.index]["day"]}"
alarm_description = "oldest meessage alarm: SQS ${local.oldest_message_alert_source[count.index]["queue_name"]} > ${local.oldest_message_alert_source[count.index]["day"]} day "
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
metric_name = "ApproximateAgeOfOldestMessage"
namespace = "AWS/SQS"
period = 300
statistic = "Minimum"
threshold = local.oldest_message_alert_source[count.index]["seconds"]
alarm_actions = [aws_sns_topic.fatal.arn]
ok_actions = [aws_sns_topic.fatal.arn]
insufficient_data_actions = []
treat_missing_data = "ignore" //欠落データを無視
dimensions = {
QueueName = local.oldest_message_alert_source[count.index]["queue_name"]
}
}
aws_cloudwatch_metric_alarm.queue_count_alarm
では「キュー数監視」
aws_cloudwatch_metric_alarm oldest_message_days
では「放置されたメッセージの日数」を監視しています。
これで最低限のものは設定できるかと思います。
何度も同じlocal変数へのアクセスや[count.index]が出てきてしまうのが少し悩みどころですね。
このへんはCDKやら使っていると、「もうすこし素直にデータ変換やループ定義したいなあ」と思ってしまいます。
tfでももうすこしスマートになら無いかと思うので、綺麗なやり方募集です。