🕌
ECSのタスク停止イベントをSlackへ通知させる
はじめに
AWSリソースやアプリケーションの状態を、Slackに通知させたいシチュエーションは多々あるかと思います。今回は、ECSタスクが停止したタイミングでSlackチャンネルに通知する実装を、Event BridgeのAPI Destinationのみで実現してみます。※実装にはTerraformを使用します。
前提条件
- SlackのWebhook URLは取得済み。
- ECSクラスターは構築済み。
まとめ
Event BridgeのみでSlackに通知させること自体は可能だが、イベントのフィルタリングや通知内容のカスタマイズ性に乏しいため、間にChatBotやLambdaを噛ませた方が良さそう。
実装
resource "aws_cloudwatch_event_rule" "main" {
name = "demo-ecs-alert"
event_pattern = jsonencode({
source : ["aws.ecs"],
detail-type : ["ECS Task State Change"],
detail : {
clusterArn : ["arn:aws:ecs:ap-northeast-1:xxxxxxx"],
lastStatus : ["STOPPED"]
}
})
}
トリガーとなる条件を
event_pattern
に記述します。異常終了したタスクのみ検知したいので、上記のような条件になっています。タスク状態変更イベントをログから調査するのが面倒だったので、コンソールからポチポチイベントルールを出力したが楽でした。JSON形式なのでそのままコピペできます。
resource "aws_cloudwatch_event_api_destination" "main" {
name = "demo-api"
connection_arn = aws_cloudwatch_event_connection.main.arn
invocation_endpoint = "{SlackWebhookURL}"
invocation_rate_limit_per_second = 10
http_method = "POST"
}
resource "aws_cloudwatch_event_connection" "main" {
name = "demo-connection"
authorization_type = "API_KEY"
# Slack連携では認証は不要なのでダミー
auth_parameters {
api_key {
key = "Authorization"
value = "dummy"
}
}
}
ここでは、Event Bridgeの接続先を定義します。
API_KEY
,BASIC
,OAUTH_CLIENT_CREDENTIALS
いずれかの認証方式が必須のため、ダミーのAPIキーを作成します。
resource "aws_cloudwatch_event_target" "main" {
rule = aws_cloudwatch_event_rule.main.name
arn = aws_cloudwatch_event_api_destination.main.arn
role_arn = aws_iam_role.eventbridge_role.arn
input_transformer {
input_paths = {
account = "$.account"
region = "$.region"
availabilityZone = "$.detail.availabilityZone"
stopCode = "$.detail.stopCode"
stoppedAt = "$.detail.stoppedAt"
stoppedReason = "$.detail.stoppedReason"
serviceName = "$.detail.group"
}
input_template = <<EOF
{
"attachments": [
{
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":warning: `<serviceName>` の ECS タスクが停止しました。 :warning:"
}
},
{
"type": "section",
"fields": [
{
"type": "mrkdwn",
"text": "*AWSアカウント:*\n`<account>`"
},
{
"type": "mrkdwn",
"text": "*リージョン:*\n`<region>`"
},
{
"type": "mrkdwn",
"text": "*アベイラビリティゾーン:*\n`<availabilityZone>`"
},
{
"type": "mrkdwn",
"text": "*停止コード:*\n`<stopCode>`"
},
{
"type": "mrkdwn",
"text": "*停止日時:*\n`<stoppedAt>`"
},
{
"type": "mrkdwn",
"text": "*停止理由:*\n`<stoppedReason>`"
}
]
}
]
}
]
}
EOF
}
}
ここでSlackへの通知メッセージを書いてます。JSONパスでAWSアカウントID等の情報を定義していて、
event_pattern
にマッチしたAWSイベントを自動的に渡しています。
# IAM Role/Policy for Event Bridge
resource "aws_iam_role" "eventbridge_role" {
name = local.eventbridge_role_name
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "sts:AssumeRole"
Effect = "Allow"
Principal = {
Service = "events.amazonaws.com"
}
}]
})
}
resource "aws_iam_policy" "eventbridge_policy" {
name = local.eventbridge_policy_name
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Action = "events:InvokeApiDestination"
Effect = "Allow"
Resource = aws_cloudwatch_event_api_destination.main.arn
}]
})
}
resource "aws_iam_role_policy_attachment" "eventbridge_attachment" {
role = aws_iam_role.eventbridge_role.name
policy_arn = aws_iam_policy.eventbridge_policy.arn
}
EventBridge → API Destination(外部エンドポイント呼び出し)を許可するためのロールになります。
Discussion