6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

KDDI EngineerAdvent Calendar 2020

Day 16

CloudWatchアラームをLambdaでGoogle Chatに投稿する

Last updated at Posted at 2020-12-15

#概要

CloudWatch メトリクスアラームを使用し AWS リソースの監視を開始する上で、通知を Google Chat にも投稿する必要が出てきたため、Lambda ファンクションを使用し、 SNS をトリガーにして Google Chat 連携を行いました。
本記事では、AWS CDK を利用して SNS トピックの作成 および、lambda リソースの作成を行い、 SNS のテストトピックを発行し、 Google Chatに通知が来るまで確認してみたいと思います。
実際の運用では、監視対象の CloudWatch メトリクスアラーム と 上記で作成した SNSトピックの紐付けを行うことで、アラーム発砲から Google Chat 通知までの一連の流れを実現することができます。

#前提

・ Goole Chatのチャットルームを作成し、Webhook の URLを取得している
・ AWS CDK デプロイ環境が整っている

AWS CDK にて SNS/Lambda リソースの作成

実装は以下になります。
CDK context を利用して、 Webhook の URL を渡してあげて、 Lambda の環境変数に展開しています。。

DevopsAlarmStack.ts
import * as cdk from "@aws-cdk/core";
import * as sns from "@aws-cdk/aws-sns";
import * as iam from "@aws-cdk/aws-iam";
import * as lambda from "@aws-cdk/aws-lambda";
import * as subscriptions from "@aws-cdk/aws-sns-subscriptions";

export class DevopsAlarmStack extends cdk.Stack {
  constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const webhookURL = this.node.tryGetContext("webhookURL") || "";

    // lambda用ロール作成
    const lambdaIamRole = new iam.Role(
      this,
      "test-iam-role-for-lambda-devops-alarm",
      {
        roleName: "test-iam-role-for-lambda-devops-alarm",
        assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
        managedPolicies: [
          iam.ManagedPolicy.fromAwsManagedPolicyName(
            "service-role/AWSLambdaBasicExecutionRole"
          ),
        ],
      }
    );

    // SNS トピック作成
    const myTopic = new sns.Topic(this, "test-alarm-topic", {
      displayName: "test-alarm-topic",
      topicName: "test-alarm-topic",
    });

    // 通知用 lambda 作成
    const myFunction = new lambda.Function(
      this,
      "test-lambda-alarm-handler",
      {
        code: lambda.Code.fromAsset("../src", {
          exclude: ["*.ts", "cdk.out"],
        }),
        handler: "AlarmHandler.handler",
        functionName: "test-lambda-alarm-handler",
        runtime: lambda.Runtime.NODEJS_12_X,
        role: lambdaIamRole,
        environment: {
          HANGOUT_WEBHOOK_URL: `${webhookURL}`,
        },
      }
    );

    // SNS と lambda の紐付け
    myTopic.addSubscription(new subscriptions.LambdaSubscription(myFunction));
  }
}

Lambda 内関数の実装

Lambda 内の実装は以下になります。
Lambda で展開された環境変数から HANGOUT_WEBHOOK_URL を取得し、利用しています。
SNS から渡ってきたイベントを、見やすいように整形して、Google Chat Webhook API を利用し、通知してあげます。

AlarmHandler.ts
const fetch = require("node-fetch");

const webhookURL = process.env.HANGOUT_WEBHOOK_URL;

export const handler = async (event: any) => {
  const text = get_text(get_message_from_event(event));

  console.log(text);
  await fetch(webhookURL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json; charset=UTF-8",
    },
    body: JSON.stringify({
      text: text,
    }),
  }).then((response: any) => {
    console.log(response);
  });
};

function get_message_from_event(event: any) {
  return JSON.parse(event.Records[0].Sns.Message);
}

function get_text(message: any) {
  const alarm_name = "AlarmName" in message ? message["AlarmName"] : "";
  const old_state = "OldStateValue" in message ? message["OldStateValue"] : "";
  const new_state = "NewStateValue" in message ? message["NewStateValue"] : "";
  const new_state_reason =
    "NewStateReason" in message ? message["NewStateReason"] : "";
  return (
    "*" +
    alarm_name +
    ":* " +
    old_state +
    "" +
    new_state +
    "\n```" +
    new_state_reason +
    "```"
  );
}

SNS テストトピックの発行

AWS コンソールにて下記の json メッセージを発行します。
[Amazon SNS] - [トピック] - [上記のCDKにて作成したトピックを選択] - [メッセージの発行]

message.json
{
    "AlarmName": "sample-error",
    "AlarmDescription": "sampleでエラーが発生しました。",
    "AWSAccountId": "xxxxxxxxxxxx",
    "NewStateValue": "ALARM",
    "NewStateReason": "Threshold Crossed: 1 datapoint [2.0 (29/11/17 01:09:00)] was greater than or equal to the threshold (1.0).",
    "StateChangeTime": "2017-11-29T01:10:32.907+0000",
    "Region": "Asia Pacific (Tokyo)",
    "OldStateValue": "OK",
    "Trigger": {
        "MetricName": "sample-metric",
        "Namespace": "LogMetrics",
        "StatisticType": "Statistic",
        "Statistic": "SUM",
        "Unit": null,
        "Dimensions": [],
        "Period": 60,
        "EvaluationPeriods": 1,
        "ComparisonOperator": "GreaterThanOrEqualToThreshold",
        "Threshold": 1,
        "TreatMissingData": "- TreatMissingData:                    NonBreaching",
        "EvaluateLowSampleCountPercentile": ""
    }
}

※ サンプルのJSONデータは、https://qiita.com/onooooo/items/f59c69e30dc5b477f9fd を参考にさせていただきました。

Google Chat での確認

Google Chat に以下のような形で、通知を取得することができました。

スクリーンショット 2020-12-15 18.36.01.png

#まとめ

AWS CDK を利用して SNS トピックの作成 および、lambda リソースの作成を行い、 SNS のテストトピックを発行し、 Google Chatに通知が来るまでを確認してみました。普段 Google Chat を利用されている方は、AWSリソースに何か生じた際にすぐ通知が来てくれるので便利だと思います。

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?