09. CloudWatch / SNS / SQS
運用に必須の 「ログ・メトリクス・通知・キュー」。CloudWatch でログとメトリクスを取り、メトリクスのしきい値超過を SNS で通知、Lambda 等の非同期処理は SQS で受ける。AWS 運用の基本セット。
この章の目次
aws_cloudwatch_log_group
CloudWatch Logs はログの保管庫。ロググループ という単位でログを束ねます。Lambda、ECS、API Gateway などはここに書き込みます。
resource "aws_cloudwatch_log_group" "lambda" {
name = "/aws/lambda/hello"
retention_in_days = 14 # ← 重要。指定しないと「無期限」になり料金が膨らむ
}
resource "aws_cloudwatch_log_group" "api" {
name = "/aws/apigw/hello-api"
retention_in_days = 14
}
resource "aws_cloudwatch_log_group" "ecs" {
name = "/ecs/myapp"
retention_in_days = 30
kms_key_id = aws_kms_key.logs.arn # 任意: KMS で暗号化
}
retention_in_days を必ず
デフォルトは「無期限保持」= ログが永久に増え続けます。費用事故の代表例。初学者は必ず 7〜30 日で設定。
サブスクリプションフィルタ(外部送信)
# CloudWatch Logs → Kinesis → 外部 SaaS という流れの最初の 1 ステップ
resource "aws_cloudwatch_log_subscription_filter" "to_kinesis" {
name = "to-kinesis"
log_group_name = aws_cloudwatch_log_group.lambda.name
filter_pattern = "" # 全件
destination_arn = aws_kinesis_stream.logs.arn
role_arn = aws_iam_role.logs_to_kinesis.arn
}
aws_cloudwatch_metric_alarm
「特定のメトリクスが、N 期間連続でしきい値を超えたら、X に通知する」を定義。
resource "aws_cloudwatch_metric_alarm" "lambda_errors" {
alarm_name = "lambda-hello-errors"
alarm_description = "Lambda hello のエラーが 5 分間で 5 回を超えた"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
threshold = 5
metric_name = "Errors"
namespace = "AWS/Lambda"
period = 300 # 5 分
statistic = "Sum"
dimensions = {
FunctionName = aws_lambda_function.hello.function_name
}
alarm_actions = [aws_sns_topic.alerts.arn]
ok_actions = [aws_sns_topic.alerts.arn]
treat_missing_data = "notBreaching"
}
典型的なアラーム例
| 監視対象 | namespace | metric_name |
|---|---|---|
| Lambda エラー | AWS/Lambda | Errors |
| EC2 CPU | AWS/EC2 | CPUUtilization |
| RDS CPU | AWS/RDS | CPUUtilization |
| RDS 接続数 | AWS/RDS | DatabaseConnections |
| ALB 5xx | AWS/ApplicationELB | HTTPCode_Target_5XX_Count |
| SQS 積み残し | AWS/SQS | ApproximateNumberOfMessagesVisible |
aws_sns_topic と購読
SNS は 「pub/sub」 の仕組み。トピックに publish したメッセージが、購読者全員に配信されます。アラートメール/Slack 連携/他サービスへの fan-out で頻出。
resource "aws_sns_topic" "alerts" {
name = "alerts"
kms_master_key_id = "alias/aws/sns"
}
# メール購読
resource "aws_sns_topic_subscription" "email" {
topic_arn = aws_sns_topic.alerts.arn
protocol = "email"
endpoint = "ops@example.com"
}
# Slack: AWS Chatbot 経由(推奨)
resource "aws_sns_topic_subscription" "slack" {
topic_arn = aws_sns_topic.alerts.arn
protocol = "https"
endpoint = var.chatbot_webhook # AWS Chatbot で発行した URL
}
# Lambda 購読(イベント駆動の処理)
resource "aws_sns_topic_subscription" "lambda" {
topic_arn = aws_sns_topic.alerts.arn
protocol = "lambda"
endpoint = aws_lambda_function.notify.arn
}
resource "aws_lambda_permission" "from_sns" {
statement_id = "AllowSNSInvoke"
action = "lambda:InvokeFunction"
function_name = aws_lambda_function.notify.function_name
principal = "sns.amazonaws.com"
source_arn = aws_sns_topic.alerts.arn
}
メール購読は AWS から確認メールが飛び、ユーザーが「Confirm subscription」リンクをクリックして初めて有効になります。
aws_sqs_queue(DLQ 含む)
SQS は キュー。送信側と受信側を疎結合にし、受信側がダウンしてもメッセージが滞留するだけで消えません。
resource "aws_sqs_queue" "jobs_dlq" {
name = "jobs-dlq"
message_retention_seconds = 1209600 # 14 日(最大)
kms_master_key_id = "alias/aws/sqs"
}
resource "aws_sqs_queue" "jobs" {
name = "jobs"
visibility_timeout_seconds = 60 # ワーカが処理する想定時間
message_retention_seconds = 345600 # 4 日
kms_master_key_id = "alias/aws/sqs"
redrive_policy = jsonencode({
deadLetterTargetArn = aws_sqs_queue.jobs_dlq.arn
maxReceiveCount = 5 # 5 回失敗したら DLQ へ
})
}
キューポリシー(送信元の制限)
data "aws_iam_policy_document" "sqs_jobs" {
statement {
sid = "AllowSNSToPublish"
effect = "Allow"
actions = ["sqs:SendMessage"]
principals {
type = "Service"
identifiers = ["sns.amazonaws.com"]
}
resources = [aws_sqs_queue.jobs.arn]
condition {
test = "ArnEquals"
variable = "aws:SourceArn"
values = [aws_sns_topic.events.arn]
}
}
}
resource "aws_sqs_queue_policy" "jobs" {
queue_url = aws_sqs_queue.jobs.id
policy = data.aws_iam_policy_document.sqs_jobs.json
}
SNS → SQS の fan-out パターン
同じイベントを複数の処理系に届けたい時の定番。
[Producer] ──→ [SNS Topic "events"]
│
┌──────────┼──────────┐
↓ ↓ ↓
[SQS A] [SQS B] [Lambda]
│ │ │
↓ ↓ ↓
[Worker A] [Worker B] [Logger]
resource "aws_sns_topic_subscription" "to_sqs_a" {
topic_arn = aws_sns_topic.events.arn
protocol = "sqs"
endpoint = aws_sqs_queue.a.arn
}
resource "aws_sns_topic_subscription" "to_sqs_b" {
topic_arn = aws_sns_topic.events.arn
protocol = "sqs"
endpoint = aws_sqs_queue.b.arn
}
SNS が 1 メッセージを受けると、SQS A・B の両方に同じ内容が配信される。それぞれのワーカは自分のキューを独立した速度で処理できる、というのがこのパターンの強み。