見出し画像

[AWS CDK] CloudWatchアラームをChatbotからSlackに連携してみた

みなさんこんにちは! 第4開発事業部のAKIHISAです!

DevOpsが叫ばれる今、監視情報は開発者にとっても有益な情報です

システムの重大な異常の検知→調査・改修が迅速にできたら言うことはありません

監視情報をメールや監視ダッシュボードだけでは無く、普段目にしているチャットに通知したら監視情報の連携はよりスムーズになります

そこで、今回はAWSの監視サービスであるCloudWatchアラームから、一般的に使われているチャットツールであるSlackへの連携方法を紹介します!

この記事を書いているALHには 20名を超えるAWS資格コンプリート者が在籍中!

【ライターの紹介】
AKIHISA
第4開発事業部所属のAWSがちょっと得意な開発エンジニア
近所に最近できたコーヒーショップにどハマり中


やること

CloudWatchアラームにてアラーム状態となったメトリクスを、Slackに通知を行います

アーキテクチャ

前提条件

AWS CDKをデプロイできる状態
参考

Slackのワークスペースが存在する状態
参考

作業概要

  1. AWS ChatbotとSlackの事前設定

  2. AWS CDKデプロイ

  3. 動作確認

AWS ChatbotとSlackの事前設定

AWS Chatbotの事前設定

Chatbotは2024年2月現在、CLI及びIaCでのチャットクライアントの設定を行うことができません

ChatbotコンソールからSlackワークスペースとの連携を行います

チャットクライアントからSlackを選択してクライアントを設定を押下します

ChatbotがSlackワークスペースにアクセスする権限をリクエストされるので、許可するを押下します

SlackのワークスペースにAWS Chatbotアプリが追加されています

Slackの設定

チャンネルを作成します

作成したチャンネルへ以下のメッセージを送信(スラッシュコマンドの実行)し、AWS Chatbotをチャンネルに追加します

/invite @aws

Slack情報の取得

ワークスペースIDとチャンネルIDが必要なのでそれぞれ取得します

ワークスペースのIDはChatbotのコンソール上から取得するのが簡単です
(Tから始まる番号)

チャンネルIDは、Slackにて作成したチャンネルのチャンネル情報の最下部に表示されています
(Cから始まる番号)

AWS CDKデプロイ

作成するスタックは以下の2つのL3コンストラクタからなっています

  • CloudWatchアラームが設定されているサンプルリソース(Lmabda)のコンストラクタ

  • アラームをモニタリングしているコンストラクタ

lib/construct/sample-resource.ts

import * as cdk from 'aws-cdk-lib';
import { aws_cloudwatch as cw, aws_cloudwatch_actions as cwa, aws_lambda as lambda, aws_sns as sns } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export interface sampleResourceProps {
  topic: sns.Topic;
}
export class sampleResource extends Construct {
  constructor(scope: Construct, id: string, props: sampleResourceProps) {
    super(scope, id);

    const func = new lambda.Function(this, 'Function', {
      functionName: 'SampleFunction',
      runtime: lambda.Runtime.PYTHON_3_11,
      handler: 'index.lambda_handler',
      code: lambda.Code.fromInline(
        `def lambda_handler(event, context):
          message = "Hello, World!"
          return message`,
      ),
    });
    const errorsAlarm = new cw.Metric({
      dimensionsMap: {
        FunctionName: func.functionName,
      },
      namespace: 'AWS/Lambda',
      metricName: 'Errors',
      period: cdk.Duration.minutes(5),
      statistic: cw.Stats.SUM,
    }).createAlarm(this, 'SampleFunctionErrors', {
      alarmName: 'SampleFunctionAlarm-Erros',
      evaluationPeriods: 1,
      threshold: 1,
      comparisonOperator: cw.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
    });
    errorsAlarm.addAlarmAction(new cwa.SnsAction(props.topic));

    const throttlesAlarm = new cw.Metric({
      dimensionsMap: {
        FunctionName: func.functionName,
      },
      namespace: 'AWS/Lambda',
      metricName: 'Throttles',
      period: cdk.Duration.minutes(5),
      statistic: cw.Stats.SUM,
    }).createAlarm(this, 'SampleFunctionThrottles', {
      alarmName: 'SampleFunctionAlarm-Throttles',
      evaluationPeriods: 1,
      threshold: 1,
      comparisonOperator: cw.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD,
    });
    throttlesAlarm.addAlarmAction(new cwa.SnsAction(props.topic));
  }
}

lib/construct/monitoring.ts

import { aws_chatbot as chatbot, aws_sns as sns } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export class monitoring extends Construct {
  public readonly topic: sns.Topic;
  constructor(scope: Construct, id: string) {
    super(scope, id);

    const topic = new sns.Topic(this, 'Topic', {
      topicName: 'SampleTopic',
    });
    this.topic = topic;

    new chatbot.SlackChannelConfiguration(this, 'Channel', {
      slackChannelConfigurationName: 'SampleMonitoringChannel',
      slackWorkspaceId: '[ワークスペースID]',
      slackChannelId: '[チャンネルID]',
      notificationTopics: [topic],
    });
  }
}

lib/stack/sample-app-stack.ts

import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { monitoring } from '../construct/monitoring';
import { sampleResource } from '../construct/sample-resource';

export class SampleAppStack extends Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);
    const monitor = new monitoring(this, 'AlarmNortification');
    new sampleResource(this, 'SampleResource', {
      topic: monitor.topic,
    });
  }
}

CDKデプロイを行います

cdk deploy

スタックが作成されました!

CloudFormationコンソール

動作確認

CloudWatchアラームをアラーム状態にさせます
CloudShellを開き、以下のコマンドを実行します

CloudShellコンソール

aws cloudwatch set-alarm-state --alarm-name "SampleFunctionAlarm-Erros" --state-value "ALARM" --state-reason "test"

参考

SlackチャンネルにCloudWatchアラームの通知が送信されていました!

もう一つのCloudWatchアラームもアラーム状態にします

aws cloudwatch set-alarm-state --alarm-name "SampleFunctionAlarm-Throttles" --state-value "ALARM" --state-reason "test"

こちらもアラームの通知が送信されています

まとめ

CloudWatchアラームをSlackへ迅速へ通知することができました

CDKのコードから分かる通り、CloudWatchアラームをSNSトピックへ送信するだけで追加のアラームを通知することもできるため、拡張性も高いです

errorsAlarm.addAlarmAction(new cwa.SnsAction(props.topic));

是非、ChatOpsを推進させて、対インシデント耐性の高いシステムを構築していきましょう!

ALHについて知る



↓ ↓ ↓ 採用サイトはこちら ↓ ↓ ↓


↓ ↓ ↓ コーポレートサイトはこちら ↓ ↓ ↓


↓ ↓ ↓ もっとALHについて知りたい? ↓ ↓ ↓